home *** CD-ROM | disk | FTP | other *** search
/ ShareWare OnLine 2 / ShareWare OnLine Volume 2 (CMS Software)(1993).iso / os2 / memsz161.zip / MEMSIZE.C < prev    next >
C/C++ Source or Header  |  1993-04-09  |  129KB  |  3,942 lines

  1. /****************************************************************** MEMSIZE.C
  2.  *                                        *
  3.  * System Resources Monitor                            *
  4.  *                                        *
  5.  * Revision 1.61 (09 April 1993)                        *
  6.  *                                        *
  7.  * (C) Copyright 1991-1993 by Richard W. Papo.                    *
  8.  *                                        *
  9.  * This is 'FreeWare'.    As such, it may be copied and distributed        *
  10.  * freely.  If you want to use part of it in your own program, please        *
  11.  * give credit where credit is due.  If you want to change the            *
  12.  * program, please refer the change request to me or send me the        *
  13.  * modified source code.  I can be reached at CompuServe 72607,3111.        *
  14.  *                                        *
  15.  ****************************************************************************/
  16.  
  17. #define INCL_BASE
  18. #define INCL_PM
  19. #include <os2.h>
  20.  
  21. #include <direct.h>
  22. #include <process.h>
  23. #include <stdarg.h>
  24. #include <stddef.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <time.h>
  29.  
  30. #include <sys\types.h>
  31. #include <sys\stat.h>
  32.  
  33. #include "debug.h"
  34. #include "support.h"
  35. #include "about.h"
  36. #include "settimer.h"
  37.  
  38. #include "memsize.h"
  39.  
  40.  
  41. /****************************************************************************
  42.  *                                        *
  43.  *             Definitions & Declarations                *
  44.  *                                        *
  45.  ****************************************************************************/
  46.  
  47.   // Constants
  48.  
  49. #define PROGRAM_NAME        "MEMSIZE"
  50. #define CLASS_NAME        "MEMSIZE"
  51.  
  52. enum
  53. {
  54.   ITEM_CLOCK,
  55.   ITEM_MEMORYFREE,
  56.   ITEM_SWAPFILESIZE,
  57.   ITEM_SWAPDISKFREE,
  58.   ITEM_SPOOLFILESIZE,
  59.   ITEM_CPULOAD,
  60.   ITEM_TASKCOUNT,
  61.   ITEM_BASE_COUNT
  62. } ;
  63.  
  64. #define WM_REFRESH        WM_USER
  65.  
  66. #define MAX_DRIVES      26
  67. #define DRIVE_ERROR      0xFFFFFFFFL
  68.  
  69.  
  70.   // Data Types
  71.  
  72. typedef struct          // Data structure for item to be monitored.
  73. {
  74.   CHAR     Name [80] ;           // Text for item's profile name.
  75.   BOOL     Flag ;            // Flag: Show this item at this time?
  76.   CHAR     Label [80] ;           // Text to display on left part of line.
  77.   ULONG  Value ;           // Value to display on right part of line.
  78.   BOOL     Error ;           // Flag: Drive has had an error.
  79.   CHAR     MenuOption [80] ;     // Text to display in system menu.
  80.   USHORT MenuId ;           // ID for use in system menu.
  81.   ULONG  (*NewValue)           // Function to determine new value.
  82.     (PVOID,USHORT) ;
  83.   USHORT Parm ;            // Parameter to pass to NewValue function.
  84.   USHORT Divisor ;           // Amount to divide value by before display.
  85.   CHAR     Suffix ;           // Character to place after value.
  86. }
  87. ITEM, *PITEM ;
  88.  
  89. typedef struct          // Parameters saved to system.
  90. {
  91.   PITEM  Items ;        // Items to display.
  92.   int     ItemCount ;
  93.  
  94.   SWP     Position ;        // Window size & location.
  95.   BOOL     fPosition ;
  96.  
  97.   BOOL     HideControls ;     // User options.
  98.   BOOL     fHideControls ;
  99.  
  100.   USHORT TimerInterval ;
  101.   BOOL     fTimerInterval ;
  102.  
  103.   CHAR     FontNameSize [80] ;    // Presentation Parameters
  104.   BOOL     fFontNameSize ;
  105.  
  106.   COLOR  BackColor ;
  107.   BOOL     fBackColor ;
  108.  
  109.   COLOR  TextColor ;
  110.   BOOL     fTextColor ;
  111. }
  112. PROFILE, *PPROFILE ;
  113.  
  114. typedef struct        // Data structure for window.
  115. {
  116.   HAB         Anchor ;
  117.   HMODULE     Library ;
  118.  
  119.   ULONG      MaxCount ;
  120.   ULONG      IdleCounter ;
  121.   ULONG      IdleCount ;
  122.   TID         IdleLoopTID ;
  123.   TID         MonitorLoopTID ;
  124.  
  125.   PROFILE     Profile ;
  126.  
  127.   HWND           hwndTitleBar ;
  128.   HWND           hwndSysMenu ;
  129.   HWND         hwndMinMax ;
  130.  
  131.   ULONG      Drives ;
  132.  
  133.   char           SwapPath [_MAX_PATH] ;
  134.   int         MinFree ;
  135.  
  136.   PCHAR      SpoolPath ;
  137.  
  138.   long         Width ;
  139.   long         Height ;
  140.  
  141.   COUNTRYINFO     CountryInfo ;
  142. }
  143. DATA, *PDATA ;
  144.  
  145. typedef struct
  146. {
  147.   HAB Anchor ;
  148.   HMODULE Library ;
  149. }
  150. PARMS, *PPARMS ;
  151.  
  152. typedef struct
  153. {
  154.   volatile PULONG Counter ;
  155.   PUSHORT Interval ;
  156.   HWND Owner ;
  157. }
  158. MONITOR_PARMS, *PMONITOR_PARMS ;
  159.  
  160.  
  161.   // Function Prototypes
  162.  
  163. extern void main ( int argc, PCHAR argv[] ) ;
  164.  
  165. static MRESULT EXPENTRY MessageProcessor
  166. (
  167.   HWND hwnd,
  168.   USHORT msg,
  169.   MPARAM mp1,
  170.   MPARAM mp2
  171. ) ;
  172.  
  173. static METHODFUNCTION Create ;
  174. static METHODFUNCTION Destroy ;
  175. static METHODFUNCTION Size ;
  176. static METHODFUNCTION SaveApplication ;
  177. static METHODFUNCTION Paint ;
  178. static METHODFUNCTION Command ;
  179. static METHODFUNCTION ResetDefaults ;
  180. static METHODFUNCTION HideControlsCmd ;
  181. static METHODFUNCTION SetTimer ;
  182. static METHODFUNCTION About ;
  183. static METHODFUNCTION ButtonDown ;
  184. static METHODFUNCTION ButtonDblClick ;
  185. static METHODFUNCTION PresParamChanged ;
  186. static METHODFUNCTION SysColorChange ;
  187. static METHODFUNCTION QueryKeysHelp ;
  188. static METHODFUNCTION HelpError ;
  189. static METHODFUNCTION ExtHelpUndefined ;
  190. static METHODFUNCTION HelpSubitemNotFound ;
  191. static METHODFUNCTION Refresh ;
  192.  
  193. static void GetProfile ( HAB Anchor, HMODULE Library, PPROFILE Profile ) ;
  194. static void PutProfile ( PPROFILE Profile ) ;
  195.  
  196. static PCHAR ScanSystemConfig ( PCHAR Keyword ) ;
  197.  
  198. static void ResizeWindow ( HWND hwnd, PPROFILE Profile ) ;
  199.  
  200. static void HideControls
  201. (
  202.   BOOL fHide,
  203.   HWND hwndFrame,
  204.   HWND hwndSysMenu,
  205.   HWND hwndTitleBar,
  206.   HWND hwndMinMax
  207. ) ;
  208.  
  209. static void UpdateWindow ( HWND hwnd, PDATA Data, BOOL All ) ;
  210.  
  211. static ULONG ComputeTime       ( PDATA Data, USHORT Dummy ) ;
  212. static ULONG ComputeFreeMemory ( PDATA Data, USHORT Dummy ) ;
  213. static ULONG ComputeSwapSize   ( PDATA Data, USHORT Dummy ) ;
  214. static ULONG ComputeSwapFree   ( PDATA Data, USHORT Dummy ) ;
  215. static ULONG ComputeSpoolSize  ( PDATA Data, USHORT Dummy ) ;
  216. static ULONG ComputeCpuLoad    ( PDATA Data, USHORT Dummy ) ;
  217. static ULONG ComputeTaskCount  ( PDATA Data, USHORT Dummy ) ;
  218. static ULONG ComputeDriveFree  ( PDATA Data, USHORT Drive ) ;
  219.  
  220. static void _far _cdecl MonitorLoopThread ( PMONITOR_PARMS Parms ) ;
  221.  
  222. static VOID UpdateDriveList
  223. (
  224.   HAB Anchor,
  225.   HMODULE Library,
  226.   PPROFILE Profile,
  227.   ULONG OldDrives,
  228.   ULONG NewDrives
  229. ) ;
  230.  
  231. static BOOL CheckDrive ( USHORT Drive, PBYTE FileSystem ) ;
  232.  
  233. static VOID RebuildDisplayItems ( HWND hwnd, PDATA Data ) ;
  234.  
  235. static ULONG CalibrateLoadMeter ( void ) ;
  236.  
  237. static void _far _cdecl CounterThread ( PULONG Counter ) ;
  238.  
  239.  
  240.   // Global Data (private)
  241.  
  242. static HSEM ItemSemaphore ;
  243.  
  244. static ITEM Items [ ITEM_BASE_COUNT + MAX_DRIVES ] =
  245. {
  246.   {
  247.     "ShowTime",      TRUE, "", 0L, FALSE, "", IDM_SHOW_CLOCK,
  248.     ComputeTime,       0,    0, ' '
  249.   },
  250.  
  251.   {
  252.     "ShowMemory",    TRUE, "", 0L, FALSE, "", IDM_SHOW_MEMORY,
  253.     ComputeFreeMemory, 0, 1024, 'K'
  254.   },
  255.  
  256.   {
  257.     "ShowSwapsize",  TRUE, "", 0L, FALSE, "", IDM_SHOW_SWAPSIZE,
  258.     ComputeSwapSize,   0, 1024, 'K'
  259.   },
  260.  
  261.   {
  262.     "ShowSwapfree",  TRUE, "", 0L, FALSE, "", IDM_SHOW_SWAPFREE,
  263.     ComputeSwapFree,   0, 1024, 'K'
  264.   },
  265.  
  266.   {
  267.     "ShowSpoolSize", TRUE, "", 0L, FALSE, "", IDM_SHOW_SPOOLSIZE,
  268.     ComputeSpoolSize,  0, 1024, 'K'
  269.   },
  270.  
  271.   {
  272.     "ShowCpuLoad",   TRUE, "", 0L, FALSE, "", IDM_SHOW_CPULOAD,
  273.     ComputeCpuLoad,    0,    0, '%'
  274.   },
  275.  
  276.   {
  277.     "ShowTaskCount", TRUE, "", 0L, FALSE, "", IDM_SHOW_TASKCOUNT,
  278.     ComputeTaskCount,  0,    0, ' '
  279.   }
  280. } ;
  281.  
  282.  
  283. /****************************************************************************
  284.  *                                        *
  285.  *    Program Mainline                            *
  286.  *                                        *
  287.  ****************************************************************************/
  288.  
  289. extern void main ( int argc, PCHAR argv[] )
  290. {
  291.  /***************************************************************************
  292.   * Local Declarations                                *
  293.   ***************************************************************************/
  294.  
  295.   HELPINIT HelpInit =
  296.   {
  297.     sizeof ( HELPINIT ),
  298.     0L,
  299.     NULL,
  300.     MAKEP ( 0xFFFF, ID_MAIN ),
  301.     0,
  302.     0,
  303.     0,
  304.     0,
  305.     NULL,
  306.     CMIC_HIDE_PANEL_ID,
  307.     PROGRAM_NAME ".HLP"
  308.   } ;
  309.  
  310.   HAB Anchor ;
  311.   FRAMECDATA fcdata ;
  312.   CHAR HelpTitle [80] ;
  313.   HWND hwndClient ;
  314.   HWND hwndFrame ;
  315.   HWND hwndHelp ;
  316.   HMODULE Library ;
  317.   HMQ MessageQueue ;
  318.   PARMS Parms ;
  319.   QMSG QueueMessage ;
  320.   BOOL Reset ;
  321.   CHAR ResetCommand [40] ;
  322.   CHAR Title [80] ;
  323.  
  324.  /***************************************************************************
  325.   * Initialize for PM.    Abort if unable to do so.                *
  326.   ***************************************************************************/
  327.  
  328.   Anchor = WinInitialize ( 0 ) ;
  329.   if ( Anchor == NULL )
  330.     return ;
  331.  
  332.  /***************************************************************************
  333.   * Create the application message queue.  Abort if unable to do so.        *
  334.   ***************************************************************************/
  335.  
  336.   MessageQueue = WinCreateMsgQueue ( Anchor, 0 ) ;
  337.   if ( MessageQueue == NULL )
  338.   {
  339.     WinTerminate ( Anchor ) ;
  340.     return ;
  341.   }
  342.  
  343.  /***************************************************************************
  344.   * Now WIN and GPI calls will work.  Open the language DLL.            *
  345.   ***************************************************************************/
  346.  
  347.   if ( DosLoadModule ( NULL, 0, PROGRAM_NAME, &Library ) )
  348.   {
  349.     Debug ( HWND_DESKTOP, "ERROR: Unable to load " PROGRAM_NAME ".DLL." ) ;
  350.     WinDestroyMsgQueue ( MessageQueue ) ;
  351.     WinTerminate ( Anchor ) ;
  352.     return ;
  353.   }
  354.  
  355.  /***************************************************************************
  356.   * Register the window class.                            *
  357.   ***************************************************************************/
  358.  
  359.   if ( NOT WinRegisterClass ( Anchor, CLASS_NAME, MessageProcessor,
  360.     CS_MOVENOTIFY, sizeof(PVOID) ) )
  361.   {
  362.     CHAR Message [200] ;
  363.     char Title [80] ;
  364.  
  365.     WinLoadString ( Anchor, Library, IDS_TITLE,
  366.       sizeof(Title), Title ) ;
  367.     WinLoadString ( Anchor, Library, IDS_ERROR_WINREGISTERCLASS,
  368.       sizeof(Message), Message ) ;
  369.     WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, Message,
  370.       Title, 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  371.  
  372.     WinDestroyMsgQueue ( MessageQueue ) ;
  373.     WinTerminate ( Anchor ) ;
  374.     return ;
  375.   }
  376.  
  377.  /***************************************************************************
  378.   * Decipher command-line parameters.                        *
  379.   ***************************************************************************/
  380.  
  381.   WinLoadString ( Anchor, Library, IDS_PARMS_RESET, sizeof(ResetCommand), ResetCommand ) ;
  382.   Reset = FALSE ;
  383.  
  384.   while ( --argc )
  385.   {
  386.     argv ++ ;
  387.     strupr ( *argv ) ;
  388.     if ( *argv[0] == '?' )
  389.     {
  390.       CHAR Message [200] ;
  391.       CHAR Title [80] ;
  392.  
  393.       WinLoadString ( Anchor, Library, IDS_TITLE,
  394.     sizeof(Title), Title ) ;
  395.       WinLoadString ( Anchor, Library, IDS_PARAMETERLIST,
  396.     sizeof(Message), Message ) ;
  397.       WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, Message,
  398.     Title, 0, MB_ENTER | MB_NOICON ) ;
  399.  
  400.       WinDestroyMsgQueue ( MessageQueue ) ;
  401.       WinTerminate ( Anchor ) ;
  402.       return ;
  403.     }
  404.  
  405.     if ( !strcmp ( *argv, ResetCommand ) )
  406.     {
  407.       Reset = TRUE ;
  408.       continue ;
  409.     }
  410.  
  411.     {
  412.       CHAR Format [200] ;
  413.       CHAR Message [200] ;
  414.       CHAR Title [80] ;
  415.  
  416.       WinLoadString ( Anchor, Library, IDS_TITLE,
  417.     sizeof(Title), Title ) ;
  418.       WinLoadString ( Anchor, Library, IDS_ERROR_INVALIDPARM,
  419.     sizeof(Format), Format ) ;
  420.       sprintf ( Message, Format, *argv ) ;
  421.       WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, Message,
  422.     Title, 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  423.  
  424.       WinDestroyMsgQueue ( MessageQueue ) ;
  425.       WinTerminate ( Anchor ) ;
  426.       return ;
  427.     }
  428.   }
  429.  
  430.  /***************************************************************************
  431.   * If we're going to reset the program's profile, do it now.               *
  432.   ***************************************************************************/
  433.  
  434.   if ( Reset )
  435.   {
  436.     PrfWriteProfileData ( HINI_USERPROFILE, PROGRAM_NAME, NULL, NULL, 0 ) ;
  437.   }
  438.  
  439.  /***************************************************************************
  440.   * Create the help instance.                            *
  441.   ***************************************************************************/
  442.  
  443.   WinLoadString ( Anchor, Library, IDS_HELPTITLE, sizeof(HelpTitle), HelpTitle ) ;
  444.   HelpInit.pszHelpWindowTitle = HelpTitle ;
  445.  
  446.   hwndHelp = WinCreateHelpInstance ( Anchor, &HelpInit ) ;
  447.  
  448.   if ( hwndHelp == NULL )
  449.   {
  450.     CHAR Message [200] ;
  451.     char Title [80] ;
  452.  
  453.     WinLoadString ( Anchor, Library, IDS_TITLE,
  454.       sizeof(Title), Title ) ;
  455.     WinLoadString ( Anchor, Library, IDS_ERROR_WINCREATEHELPINSTANCE,
  456.       sizeof(Message), Message ) ;
  457.     WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, Message,
  458.       Title, 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  459.   }
  460.  
  461.  /***************************************************************************
  462.   * Create the frame window.                            *
  463.   ***************************************************************************/
  464.  
  465.   fcdata.cb = sizeof(fcdata) ;
  466.   fcdata.flCreateFlags =
  467.     FCF_TITLEBAR | FCF_SYSMENU | FCF_BORDER |
  468.       FCF_ICON | FCF_MINBUTTON | FCF_NOBYTEALIGN | FCF_ACCELTABLE ;
  469.   fcdata.hmodResources = 0 ;
  470.   fcdata.idResources   = ID_MAIN ;
  471.  
  472.   hwndFrame = WinCreateWindow
  473.   (
  474.     HWND_DESKTOP,
  475.     WC_FRAME,
  476.     "",
  477.     0,
  478.     0, 0, 0, 0,
  479.     HWND_DESKTOP,
  480.     HWND_TOP,
  481.     ID_MAIN,
  482.     &fcdata,
  483.     NULL
  484.   ) ;
  485.  
  486.   if ( hwndFrame == NULL )
  487.   {
  488.     CHAR Message [200] ;
  489.     char Title [80] ;
  490.  
  491.     WinLoadString ( Anchor, Library, IDS_TITLE,
  492.       sizeof(Title), Title ) ;
  493.     WinLoadString ( Anchor, Library, IDS_ERROR_WINCREATEFRAME,
  494.       sizeof(Message), Message ) ;
  495.     WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, Message,
  496.       Title, 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  497.  
  498.     WinDestroyMsgQueue ( MessageQueue ) ;
  499.     WinTerminate ( Anchor ) ;
  500.     return ;
  501.   }
  502.  
  503.  /***************************************************************************
  504.   * Set the title.                                *
  505.   ***************************************************************************/
  506.  
  507.   WinLoadString ( Anchor, Library, IDS_TITLE, sizeof(Title), Title ) ;
  508.   WinSetWindowText ( hwndFrame, Title ) ;
  509.  
  510.  /***************************************************************************
  511.   * Associate the help instance with the frame window.                *
  512.   ***************************************************************************/
  513.  
  514.   if ( hwndHelp )
  515.   {
  516.     WinAssociateHelpInstance ( hwndHelp, hwndFrame ) ;
  517.   }
  518.  
  519.  /***************************************************************************
  520.   * Create client window.  If this fails, destroy frame and return.        *
  521.   ***************************************************************************/
  522.  
  523.   Parms.Anchor = Anchor ;
  524.   Parms.Library = Library ;
  525.  
  526.   hwndClient = WinCreateWindow
  527.   (
  528.     hwndFrame,
  529.     CLASS_NAME,
  530.     "",
  531.     0,
  532.     0, 0, 0, 0,
  533.     hwndFrame,
  534.     HWND_BOTTOM,
  535.     FID_CLIENT,
  536.     &Parms,
  537.     NULL
  538.   ) ;
  539.  
  540.   if ( hwndClient == NULL )
  541.   {
  542.     CHAR Message [200] ;
  543.     char Title [80] ;
  544.  
  545.     WinLoadString ( Anchor, Library, IDS_TITLE,
  546.       sizeof(Title), Title ) ;
  547.     WinLoadString ( Anchor, Library, IDS_ERROR_WINCREATEWINDOW,
  548.       sizeof(Message), Message ) ;
  549.     WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, Message,
  550.       Title, 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  551.  
  552.     WinDestroyWindow ( hwndFrame ) ;
  553.     WinDestroyMsgQueue ( MessageQueue ) ;
  554.     WinTerminate ( Anchor ) ;
  555.     return ;
  556.   }
  557.  
  558.  /***************************************************************************
  559.   * Wait for and process messages to the window's queue.  Terminate         *
  560.   *   when the WM_QUIT message is received.                    *
  561.   ***************************************************************************/
  562.  
  563.   while ( WinGetMsg ( Anchor, &QueueMessage, NULL, 0, 0 ) )
  564.   {
  565.     WinDispatchMsg ( Anchor, &QueueMessage ) ;
  566.   }
  567.  
  568.  /***************************************************************************
  569.   * Destroy the window.                             *
  570.   ***************************************************************************/
  571.  
  572.   WinDestroyWindow ( hwndFrame ) ;
  573.  
  574.  /***************************************************************************
  575.   * If help instance has been created, get rid of it.                *
  576.   ***************************************************************************/
  577.  
  578.   if ( hwndHelp )
  579.   {
  580.     WinDestroyHelpInstance ( hwndHelp ) ;
  581.   }
  582.  
  583.  /***************************************************************************
  584.   * Release the library, if one's been loaded.                              *
  585.   ***************************************************************************/
  586.  
  587.   if ( Library )
  588.   {
  589.     DosFreeModule ( Library ) ;
  590.   }
  591.  
  592.  /***************************************************************************
  593.   * Discard all that was requested of the system and terminate.         *
  594.   ***************************************************************************/
  595.  
  596.   WinDestroyMsgQueue ( MessageQueue ) ;
  597.  
  598.   WinTerminate ( Anchor ) ;
  599. }
  600.  
  601. /****************************************************************************
  602.  *                                        *
  603.  *    Window Message Processor                        *
  604.  *                                        *
  605.  ****************************************************************************/
  606.  
  607. static MRESULT EXPENTRY MessageProcessor
  608. (
  609.   HWND hwnd,
  610.   USHORT msg,
  611.   MPARAM mp1,
  612.   MPARAM mp2
  613. )
  614. {
  615.  /***************************************************************************
  616.   * Local Declarations                                *
  617.   ***************************************************************************/
  618.  
  619.   static METHOD Methods [] =
  620.   {
  621.     { WM_CREATE,        Create            },
  622.     { WM_DESTROY,        Destroy         },
  623.     { WM_SIZE,            Size            },
  624.     { WM_MOVE,            Size            },
  625.     { WM_SAVEAPPLICATION,    SaveApplication     },
  626.     { WM_PAINT,         Paint            },
  627.     { WM_BUTTON1DOWN,        ButtonDown        },
  628.     { WM_BUTTON2DOWN,        ButtonDown        },
  629.     { WM_BUTTON1DBLCLK,     ButtonDblClick        },
  630.     { WM_BUTTON2DBLCLK,     ButtonDblClick        },
  631.     { WM_PRESPARAMCHANGED,    PresParamChanged    },
  632.     { WM_SYSCOLORCHANGE,    SysColorChange        },
  633.     { WM_COMMAND,        Command         },
  634.     { HM_QUERY_KEYS_HELP,    QueryKeysHelp        },
  635.     { HM_ERROR,         HelpError        },
  636.     { HM_EXT_HELP_UNDEFINED,    ExtHelpUndefined    },
  637.     { HM_HELPSUBITEM_NOT_FOUND, HelpSubitemNotFound },
  638.     { WM_REFRESH,        Refresh         }
  639.   } ;
  640.  
  641.  /***************************************************************************
  642.   * Dispatch the message according to the method table and return the        *
  643.   *   result.  Any messages not defined above get handled by the system     *
  644.   *   default window processor.                         *
  645.   ***************************************************************************/
  646.  
  647.   return ( DispatchMessage ( hwnd, msg, mp1, mp2, Methods, sizeof(Methods)/sizeof(Methods[0]), WinDefWindowProc ) ) ;
  648. }
  649.  
  650. /****************************************************************************
  651.  *                                        *
  652.  *    Create the main window.                         *
  653.  *                                        *
  654.  ****************************************************************************/
  655.  
  656. static MRESULT APIENTRY Create
  657. (
  658.   HWND hwnd,
  659.   USHORT msg,
  660.   MPARAM mp1,
  661.   MPARAM mp2
  662. )
  663. {
  664.  /***************************************************************************
  665.   *                Declarations                    *
  666.   ***************************************************************************/
  667.  
  668.   static MENUITEM MenuItems [] =
  669.   {
  670.     { MIT_END, MIS_TEXT,      0, IDM_SAVE_APPLICATION, NULL, 0 },
  671.     { MIT_END, MIS_TEXT,      0, IDM_RESET_DEFAULTS,   NULL, 0 },
  672.     { MIT_END, MIS_TEXT,      0, IDM_HIDE_CONTROLS,    NULL, 0 },
  673.     { MIT_END, MIS_TEXT,      0, IDM_SET_TIMER,        NULL, 0 },
  674.     { MIT_END, MIS_SUBMENU,   0, IDM_DISPLAY_ITEMS,    NULL, 0 },
  675.   } ;
  676.  
  677.   static MENUITEM MenuSeparator =
  678.     { MIT_END, MIS_SEPARATOR, 0, 0, NULL, 0 } ;
  679.  
  680.   static MENUITEM MenuAbout =
  681.     { MIT_END, MIS_TEXT, 0, IDM_ABOUT, NULL, 0 } ;
  682.  
  683.   static MENUITEM MenuHelp =
  684.     { MIT_END, MIS_HELP, 0, 0, NULL, 0 } ;
  685.  
  686.   static MENUITEM MenuItem =
  687.     { MIT_END, MIS_TEXT, 0, 0, NULL, 0 } ;
  688.  
  689.   char AboutText [80] ;
  690.   PDATA Data ;
  691.   USHORT Drive ;
  692.   char HelpText [80] ;
  693.   HPS hPS ;
  694.   HWND hwndFrame ;
  695.   SHORT i ;
  696.   PMONITOR_PARMS MonitorParms ;
  697.   PPARMS Parms ;
  698.   RECTL Rectangle ;
  699.   ULONG Size ;
  700.   PCHAR Swappath ;
  701.   char Title [80] ;
  702.  
  703.  /***************************************************************************
  704.   * Allocate instance data.                            *
  705.   ***************************************************************************/
  706.  
  707.   Data = malloc ( sizeof(DATA) ) ;
  708.  
  709.   memset ( Data, 0, sizeof(DATA) ) ;
  710.  
  711.   WinSetWindowPtr ( hwnd, QWL_USER, Data ) ;
  712.  
  713.  /***************************************************************************
  714.   * Grab any parameters from the WM_CREATE message.                *
  715.   ***************************************************************************/
  716.  
  717.   Parms = (PPARMS) PVOIDFROMMP ( mp1 ) ;
  718.  
  719.   Data->Anchor = Parms->Anchor ;
  720.   Data->Library = Parms->Library ;
  721.  
  722.  /***************************************************************************
  723.   * Get the current drive mask.                         *
  724.   ***************************************************************************/
  725.  
  726.   DosQCurDisk ( &Drive, &Data->Drives ) ;
  727.  
  728.  /***************************************************************************
  729.   * Get profile data.                                *
  730.   ***************************************************************************/
  731.  
  732.   GetProfile ( Data->Anchor, Data->Library, &Data->Profile ) ;
  733.  
  734.  /***************************************************************************
  735.   * Get country information.                            *
  736.   ***************************************************************************/
  737.  
  738.   {
  739.     COUNTRYCODE CountryCode ;
  740.     USHORT Count ;
  741.     USHORT Status ;
  742.  
  743.     CountryCode.country = 0 ;
  744.     CountryCode.codepage = 0 ;
  745.  
  746.     Status = DosGetCtryInfo ( sizeof(Data->CountryInfo), &CountryCode,
  747.       &Data->CountryInfo, &Count ) ;
  748.     if ( Status )
  749.     {
  750.       char Message [80] ;
  751.       WinLoadMessage ( Data->Anchor, Data->Library, IDS_ERROR_DOSGETCTRYINFO,
  752.     sizeof(Message), Message ) ;
  753.       Debug ( hwnd, Message, Status ) ;
  754.       Data->CountryInfo.fsDateFmt = DATEFMT_MM_DD_YY ;
  755.       Data->CountryInfo.fsTimeFmt = 0 ;
  756.       Data->CountryInfo.szDateSeparator[0] = '/' ;
  757.       Data->CountryInfo.szDateSeparator[1] = 0 ;
  758.       Data->CountryInfo.szTimeSeparator[0] = ':' ;
  759.       Data->CountryInfo.szTimeSeparator[1] = 0 ;
  760.       Data->CountryInfo.szThousandsSeparator[0] = ',' ;
  761.       Data->CountryInfo.szThousandsSeparator[1] = 0 ;
  762.     }
  763.   }
  764.  
  765.  /***************************************************************************
  766.   * Get the frame handle.                            *
  767.   ***************************************************************************/
  768.  
  769.   hwndFrame = WinQueryWindow ( hwnd, QW_PARENT, FALSE ) ;
  770.  
  771.  /***************************************************************************
  772.   * Get the control window handles.                        *
  773.   ***************************************************************************/
  774.  
  775.   Data->hwndSysMenu  = WinWindowFromID ( hwndFrame, FID_SYSMENU  ) ;
  776.   Data->hwndTitleBar = WinWindowFromID ( hwndFrame, FID_TITLEBAR ) ;
  777.   Data->hwndMinMax   = WinWindowFromID ( hwndFrame, FID_MINMAX   ) ;
  778.  
  779.  /***************************************************************************
  780.   * Create the submenu window for Display Items.                *
  781.   ***************************************************************************/
  782.  
  783.   {
  784.     MENUITEM MenuItem ;
  785.     HWND hwndSysSubMenu ;
  786.     HWND hwndSubMenu ;
  787.     SHORT idSysMenu ;
  788.  
  789.     idSysMenu = SHORT1FROMMR ( WinSendMsg ( Data->hwndSysMenu, MM_ITEMIDFROMPOSITION, NULL, NULL ) ) ;
  790.     WinSendMsg ( Data->hwndSysMenu, MM_QUERYITEM, MPFROM2SHORT(idSysMenu,FALSE), MPFROMP(&MenuItem) ) ;
  791.     hwndSysSubMenu = MenuItem.hwndSubMenu ;
  792.  
  793.     hwndSubMenu = WinCreateWindow ( hwndSysSubMenu, WC_MENU, "",
  794.       WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
  795.       0, 0, 0, 0, hwndSysSubMenu, HWND_TOP, IDM_DISPLAY_ITEMS, NULL, NULL ) ;
  796.  
  797.     MenuItems[IDM_DISPLAY_ITEMS-MenuItems[0].id].hwndSubMenu = hwndSubMenu ;
  798.   }
  799.  
  800.  /***************************************************************************
  801.   * Add basic extensions to the system menu.                    *
  802.   ***************************************************************************/
  803.  
  804.   AddSysMenuItem ( hwndFrame, &MenuSeparator, NULL ) ;
  805.  
  806.   for ( i=0; i<sizeof(MenuItems)/sizeof(MenuItems[0]); i++ )
  807.   {
  808.     char MenuText [80] ;
  809.     WinLoadString ( Data->Anchor, Data->Library, i+IDS_SAVE_APPLICATION, sizeof(MenuText), MenuText ) ;
  810.     AddSysMenuItem ( hwndFrame, MenuItems+i, MenuText ) ;
  811.   }
  812.  
  813.  /***************************************************************************
  814.   * Add 'About' to the system menu.                        *
  815.   ***************************************************************************/
  816.  
  817.   AddSysMenuItem ( hwndFrame, &MenuSeparator, NULL ) ;
  818.   WinLoadString ( Data->Anchor, Data->Library, IDS_ABOUT, sizeof(AboutText), AboutText ) ;
  819.   AddSysMenuItem ( hwndFrame, &MenuAbout, AboutText ) ;
  820.  
  821.  /***************************************************************************
  822.   * Add 'Help' to the system menu.                        *
  823.   ***************************************************************************/
  824.  
  825.   WinLoadString ( Data->Anchor, Data->Library, IDS_HELP, sizeof(HelpText), HelpText ) ;
  826.   AddSysMenuItem ( hwndFrame, &MenuHelp, HelpText ) ;
  827.  
  828.  /***************************************************************************
  829.   * Build the display items menu.                        *
  830.   ***************************************************************************/
  831.  
  832.   RebuildDisplayItems ( hwnd, Data ) ;
  833.  
  834.  /***************************************************************************
  835.   * Get the SWAPPATH statement from CONFIG.SYS.                 *
  836.   ***************************************************************************/
  837.  
  838.   Swappath = ScanSystemConfig ( "SWAPPATH" ) ;
  839.  
  840.   if ( Swappath == NULL )
  841.   {
  842.     Swappath = "C:\\OS2\\SYSTEM 0" ;
  843.   }
  844.  
  845.   strupr ( Swappath ) ;
  846.  
  847.   sscanf ( Swappath, "%s %i", Data->SwapPath, &Data->MinFree ) ;
  848.  
  849.  /***************************************************************************
  850.   * Find out where the spool work directory is.                 *
  851.   ***************************************************************************/
  852.  
  853.   Data->SpoolPath = NULL ;
  854.  
  855.   if ( PrfQueryProfileSize ( HINI_PROFILE, "PM_SPOOLER", "DIR", &Size ) )
  856.   {
  857.     Data->SpoolPath = malloc ( (int)Size ) ;
  858.     if ( Data->SpoolPath )
  859.     {
  860.       if ( PrfQueryProfileData ( HINI_PROFILE, "PM_SPOOLER", "DIR", Data->SpoolPath, &Size ) )
  861.       {
  862.     BYTE *p ;
  863.     p = strchr ( Data->SpoolPath, ';' ) ;
  864.     if ( p )
  865.     {
  866.       *p = 0 ;
  867.     }
  868.       }
  869.       else
  870.       {
  871.     free ( Data->SpoolPath ) ;
  872.     Data->SpoolPath = FALSE ;
  873.       }
  874.     }
  875.   }
  876.  
  877.  /***************************************************************************
  878.   * Calibrate the old-style load meter, if the high resolution timer's      *
  879.   *   available.                                *
  880.   ***************************************************************************/
  881.  
  882.   Data->MaxCount = CalibrateLoadMeter ( ) ;
  883.   Data->MaxCount = (ULONG) max ( 1L, Data->MaxCount ) ;
  884.  
  885.  /***************************************************************************
  886.   * Start the new load meter.                            *
  887.   ***************************************************************************/
  888.  
  889.   Data->IdleLoopTID = _beginthread ( CounterThread, NULL, 1024, &Data->IdleCounter ) ;
  890.   DosSetPrty ( PRTYS_THREAD, PRTYC_IDLETIME, PRTYD_MINIMUM, Data->IdleLoopTID ) ;
  891.   DosSuspendThread ( Data->IdleLoopTID ) ;
  892.  
  893.   Data->IdleCount = 0 ;
  894.   Data->IdleCounter = 0 ;
  895.  
  896.   if ( DosSemRequest ( &ItemSemaphore, 5000 ) )
  897.   {
  898.     Log ( "ERROR: Unable to lock item list to check CPU load item status.\n" ) ;
  899.     DosSemRequest ( &ItemSemaphore, SEM_INDEFINITE_WAIT ) ;
  900.   }
  901.   if ( Data->Profile.Items[ITEM_CPULOAD].Flag )
  902.   {
  903.     DosResumeThread ( Data->IdleLoopTID ) ;
  904.   }
  905.   DosSemClear ( &ItemSemaphore ) ;
  906.  
  907.   MonitorParms = malloc ( sizeof(*MonitorParms) ) ;
  908.   MonitorParms->Counter = & Data->IdleCounter ;
  909.   MonitorParms->Interval = & Data->Profile.TimerInterval ;
  910.   MonitorParms->Owner = hwnd ;
  911.   Data->MonitorLoopTID = _beginthread ( MonitorLoopThread, NULL, 8192, MonitorParms ) ;
  912.  
  913.  /***************************************************************************
  914.   * Add the program to the system task list.                    *
  915.   ***************************************************************************/
  916.  
  917.   WinLoadString ( Data->Anchor, Data->Library, IDS_TITLE, sizeof(Title), Title ) ;
  918.   Add2TaskList ( hwndFrame, Title ) ;
  919.  
  920.  /***************************************************************************
  921.   * Position & size the window.  For some reason, we must move and size     *
  922.   *   the window to the saved position before applying the resizing        *
  923.   *   function as fine-tuning.    Maybe the positioning request fails if        *
  924.   *   the window has no size?                            *
  925.   ***************************************************************************/
  926.  
  927.   WinSetWindowPos ( hwndFrame, HWND_BOTTOM,
  928.     Data->Profile.Position.x, Data->Profile.Position.y,
  929.     Data->Profile.Position.cx, Data->Profile.Position.cy,
  930.     SWP_SIZE | SWP_MOVE | SWP_ZORDER |
  931.     ( Data->Profile.Position.fs & SWP_MINIMIZE ) |
  932.     ( Data->Profile.Position.fs & SWP_RESTORE ) ) ;
  933.  
  934.   ResizeWindow ( hwnd, &Data->Profile ) ;
  935.  
  936.  /***************************************************************************
  937.   * Hide the controls if so configured.                     *
  938.   ***************************************************************************/
  939.  
  940.   if ( Data->Profile.HideControls
  941.     AND NOT ( Data->Profile.Position.fs & SWP_MINIMIZE ) )
  942.   {
  943.     CheckMenuItem ( hwndFrame, FID_SYSMENU, IDM_HIDE_CONTROLS, Data->Profile.HideControls ) ;
  944.  
  945.     HideControls
  946.     (
  947.       TRUE,
  948.       hwndFrame,
  949.       Data->hwndSysMenu,
  950.       Data->hwndTitleBar,
  951.       Data->hwndMinMax
  952.     ) ;
  953.   }
  954.  
  955.  /***************************************************************************
  956.   * Get the saved presentation parameters and reinstate them.            *
  957.   ***************************************************************************/
  958.  
  959.   if ( Data->Profile.fFontNameSize )
  960.   {
  961.     WinSetPresParam ( hwnd, PP_FONTNAMESIZE,
  962.       strlen(Data->Profile.FontNameSize)+1, Data->Profile.FontNameSize ) ;
  963.   }
  964.  
  965.   if ( Data->Profile.fBackColor )
  966.   {
  967.     WinSetPresParam ( hwnd, PP_BACKGROUNDCOLOR,
  968.       sizeof(Data->Profile.BackColor), &Data->Profile.BackColor ) ;
  969.   }
  970.  
  971.   if ( Data->Profile.fTextColor )
  972.   {
  973.     WinSetPresParam ( hwnd, PP_FOREGROUNDCOLOR,
  974.       sizeof(Data->Profile.TextColor), &Data->Profile.TextColor ) ;
  975.   }
  976.  
  977.  /***************************************************************************
  978.   * Determine our font size.                            *
  979.   ***************************************************************************/
  980.  
  981.   hPS = WinGetPS ( hwnd ) ;
  982.   WinQueryWindowRect ( HWND_DESKTOP, &Rectangle ) ;
  983.   WinDrawText ( hPS, 1, " ", &Rectangle, 0L, 0L, DT_LEFT | DT_BOTTOM | DT_QUERYEXTENT ) ;
  984.   Data->Width  = Rectangle.xRight - Rectangle.xLeft ;
  985.   Data->Height = Rectangle.yTop - Rectangle.yBottom ;
  986.   WinReleasePS ( hPS ) ;
  987.  
  988.  /***************************************************************************
  989.   * Now that the window's in order, make it visible.                        *
  990.   ***************************************************************************/
  991.  
  992.   WinShowWindow ( hwndFrame, TRUE ) ;
  993.  
  994.  /***************************************************************************
  995.   * Success?  Return no error.                            *
  996.   ***************************************************************************/
  997.  
  998.   return ( 0 ) ;
  999.  
  1000.   hwnd = hwnd ;
  1001.   msg = msg ;
  1002.   mp1 = mp1 ;
  1003.   mp2 = mp2 ;
  1004. }
  1005.  
  1006. /****************************************************************************
  1007.  *                                        *
  1008.  *    Destroy main window.                            *
  1009.  *                                        *
  1010.  ****************************************************************************/
  1011.  
  1012. static MRESULT APIENTRY Destroy
  1013. (
  1014.   HWND hwnd,
  1015.   USHORT msg,
  1016.   MPARAM mp1,
  1017.   MPARAM mp2
  1018. )
  1019. {
  1020.  /***************************************************************************
  1021.   *                Declarations                    *
  1022.   ***************************************************************************/
  1023.  
  1024.   PDATA Data ;
  1025.  
  1026.  /***************************************************************************
  1027.   * Find the instance data.                            *
  1028.   ***************************************************************************/
  1029.  
  1030.   Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1031.  
  1032.  /***************************************************************************
  1033.   * Release the instance memory.                        *
  1034.   ***************************************************************************/
  1035.  
  1036.   free ( Data ) ;
  1037.  
  1038.  /***************************************************************************
  1039.   * We're done.                                                             *
  1040.   ***************************************************************************/
  1041.  
  1042.   return ( MRFROMSHORT ( 0 ) ) ;
  1043.  
  1044.   hwnd = hwnd ;  msg = msg ;  mp1 = mp1 ;  mp2 = mp2 ;
  1045. }
  1046.  
  1047. /****************************************************************************
  1048.  *                                        *
  1049.  *    Process window resize message.                        *
  1050.  *                                        *
  1051.  ****************************************************************************/
  1052.  
  1053. static MRESULT APIENTRY Size
  1054. (
  1055.   HWND hwnd,
  1056.   USHORT msg,
  1057.   MPARAM mp1,
  1058.   MPARAM mp2
  1059. )
  1060. {
  1061.  /***************************************************************************
  1062.   *                Declarations                    *
  1063.   ***************************************************************************/
  1064.  
  1065.   PDATA Data ;
  1066.  
  1067.   HWND hwndFrame ;
  1068.   SWP Position ;
  1069.  
  1070.  /***************************************************************************
  1071.   * Find the instance data.                            *
  1072.   ***************************************************************************/
  1073.  
  1074.   Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1075.  
  1076.  /***************************************************************************
  1077.   * Find out the window's new position and size.                            *
  1078.   ***************************************************************************/
  1079.  
  1080.   hwndFrame = WinQueryWindow ( hwnd, QW_PARENT, FALSE ) ;
  1081.  
  1082.   WinQueryWindowPos ( hwndFrame, &Position ) ;
  1083.  
  1084.   if ( NOT ( Position.fs & SWP_MINIMIZE )
  1085.     AND NOT ( Position.fs & SWP_MAXIMIZE ) )
  1086.   {
  1087.     Data->Profile.Position.x = Position.x ;
  1088.     Data->Profile.Position.y = Position.y ;
  1089.  
  1090.     Data->Profile.Position.cx = Position.cx ;
  1091.     Data->Profile.Position.cy = Position.cy ;
  1092.   }
  1093.  
  1094.  /***************************************************************************
  1095.   * If hiding the controls . . .                        *
  1096.   ***************************************************************************/
  1097.  
  1098.   if ( Data->Profile.HideControls )
  1099.   {
  1100.  
  1101.    /*************************************************************************
  1102.     * If changing to or from minimized state . . .                *
  1103.     *************************************************************************/
  1104.  
  1105.     if ( ( Position.fs & SWP_MINIMIZE ) != ( Data->Profile.Position.fs & SWP_MINIMIZE ) )
  1106.     {
  1107.  
  1108.      /***********************************************************************
  1109.       * Hide the controls if no longer minimized.                *
  1110.       ***********************************************************************/
  1111.  
  1112.       HideControls
  1113.       (
  1114.     NOT ( Position.fs & SWP_MINIMIZE ),
  1115.     hwndFrame,
  1116.     Data->hwndSysMenu,
  1117.     Data->hwndTitleBar,
  1118.     Data->hwndMinMax
  1119.       ) ;
  1120.     }
  1121.   }
  1122.  
  1123.   Data->Profile.Position.fs = Position.fs ;
  1124.  
  1125.  /***************************************************************************
  1126.   * We're done.                                                             *
  1127.   ***************************************************************************/
  1128.  
  1129.   return ( 0 ) ;
  1130.  
  1131.   hwnd = hwnd ;
  1132.   msg = msg ;
  1133.   mp1 = mp1 ;
  1134.   mp2 = mp2 ;
  1135. }
  1136.  
  1137. /****************************************************************************
  1138.  *                                        *
  1139.  *    Process SAVE APPLICATION message.                    *
  1140.  *                                        *
  1141.  ****************************************************************************/
  1142.  
  1143. static MRESULT APIENTRY SaveApplication
  1144. (
  1145.   HWND hwnd,
  1146.   USHORT msg,
  1147.   MPARAM mp1,
  1148.   MPARAM mp2
  1149. )
  1150. {
  1151.  /***************************************************************************
  1152.   *                Declarations                    *
  1153.   ***************************************************************************/
  1154.  
  1155.   PDATA Data ;
  1156.  
  1157.  /***************************************************************************
  1158.   * Find the instance data.                            *
  1159.   ***************************************************************************/
  1160.  
  1161.   Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1162.  
  1163.  /***************************************************************************
  1164.   * Call function to put all profile data out to the system.            *
  1165.   ***************************************************************************/
  1166.  
  1167.   PutProfile ( &Data->Profile ) ;
  1168.  
  1169.  /***************************************************************************
  1170.   * We're done.  Let the system complete default processing.                *
  1171.   ***************************************************************************/
  1172.  
  1173.   return ( WinDefWindowProc ( hwnd, WM_SAVEAPPLICATION, 0, 0 ) ) ;
  1174.  
  1175.   hwnd = hwnd ;
  1176.   msg = msg ;
  1177.   mp1 = mp1 ;
  1178.   mp2 = mp2 ;
  1179. }
  1180.  
  1181. /****************************************************************************
  1182.  *                                        *
  1183.  *    Repaint entire window.                            *
  1184.  *                                        *
  1185.  ****************************************************************************/
  1186.  
  1187. static MRESULT APIENTRY Paint
  1188. (
  1189.   HWND hwnd,
  1190.   USHORT msg,
  1191.   MPARAM mp1,
  1192.   MPARAM mp2
  1193. )
  1194. {
  1195.  /***************************************************************************
  1196.   *                Declarations                    *
  1197.   ***************************************************************************/
  1198.  
  1199.   PDATA Data ;
  1200.   HPS hPS ;
  1201.   RECTL Rectangle ;
  1202.  
  1203.  /***************************************************************************
  1204.   * Find the instance data.                            *
  1205.   ***************************************************************************/
  1206.  
  1207.   Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1208.  
  1209.  /***************************************************************************
  1210.   * Get presentation space and make it use RGB colors.                *
  1211.   ***************************************************************************/
  1212.  
  1213.   hPS = WinBeginPaint ( hwnd, NULL, NULL ) ;
  1214.   GpiCreateLogColorTable ( hPS, LCOL_RESET, LCOLF_RGB, 0L, 0L, NULL ) ;
  1215.  
  1216.  /***************************************************************************
  1217.   * Clear the window.                                *
  1218.   ***************************************************************************/
  1219.  
  1220.   WinQueryWindowRect ( hwnd, &Rectangle ) ;
  1221.  
  1222.   GpiMove ( hPS, (PPOINTL) &Rectangle.xLeft ) ;
  1223.   GpiSetColor ( hPS, Data->Profile.BackColor ) ;
  1224.   GpiBox ( hPS, DRO_FILL, (PPOINTL) &Rectangle.xRight, 0L, 0L ) ;
  1225.  
  1226.  /***************************************************************************
  1227.   * Release presentation space.                         *
  1228.   ***************************************************************************/
  1229.  
  1230.   WinEndPaint ( hPS ) ;
  1231.  
  1232.  /***************************************************************************
  1233.   * Update the window and return.                        *
  1234.   ***************************************************************************/
  1235.  
  1236.   UpdateWindow ( hwnd, Data, TRUE ) ;
  1237.  
  1238.   return ( 0 ) ;
  1239.  
  1240.   hwnd = hwnd ;
  1241.   msg = msg ;
  1242.   mp1 = mp1 ;
  1243.   mp2 = mp2 ;
  1244. }
  1245.  
  1246. /****************************************************************************
  1247.  *                                        *
  1248.  *    Process commands received by Main Window                *
  1249.  *                                        *
  1250.  ****************************************************************************/
  1251.  
  1252. static MRESULT APIENTRY Command
  1253. (
  1254.   HWND hwnd,
  1255.   USHORT msg,
  1256.   MPARAM mp1,
  1257.   MPARAM mp2
  1258. )
  1259. {
  1260.  /***************************************************************************
  1261.   * Local Declarations                                *
  1262.   ***************************************************************************/
  1263.  
  1264.   static METHOD Methods [] =
  1265.   {
  1266.     { IDM_SAVE_APPLICATION, SaveApplication },
  1267.     { IDM_RESET_DEFAULTS,   ResetDefaults   },
  1268.     { IDM_HIDE_CONTROLS,    HideControlsCmd },
  1269.     { IDM_SET_TIMER,        SetTimer        },
  1270.     { IDM_EXIT,         Exit        },
  1271.     { IDM_ABOUT,        About        },
  1272.   } ;
  1273.  
  1274.   USHORT Command ;
  1275.   PDATA Data ;
  1276.   short i ;
  1277.  
  1278.  /***************************************************************************
  1279.   * Find the instance data.                            *
  1280.   ***************************************************************************/
  1281.  
  1282.   Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1283.  
  1284.  /***************************************************************************
  1285.   * Process indicated command . . .                        *
  1286.   ***************************************************************************/
  1287.  
  1288.   Command = SHORT1FROMMP ( mp1 ) ;
  1289.  
  1290.  /***************************************************************************
  1291.   * Process display item commands.                        *
  1292.   ***************************************************************************/
  1293.  
  1294.   if ( DosSemRequest ( &ItemSemaphore, 5000 ) )
  1295.   {
  1296.     Log ( "ERROR: Unable to lock item list to process display item commands.\n" ) ;
  1297.     DosSemRequest ( &ItemSemaphore, SEM_INDEFINITE_WAIT ) ;
  1298.   }
  1299.   for ( i=0; i<Data->Profile.ItemCount; i++ )
  1300.   {
  1301.     PITEM Item = & Data->Profile.Items [i] ;
  1302.  
  1303.     if ( Command == Item->MenuId )
  1304.     {
  1305.       HWND hwndFrame = WinQueryWindow ( hwnd, QW_PARENT, FALSE ) ;
  1306.  
  1307.       Item->Flag = Item->Flag ? FALSE : TRUE ;
  1308.  
  1309.       if ( i == ITEM_CPULOAD )
  1310.       {
  1311.     if ( Item->Flag )
  1312.       DosResumeThread ( Data->IdleLoopTID ) ;
  1313.     else
  1314.       DosSuspendThread ( Data->IdleLoopTID ) ;
  1315.       }
  1316.  
  1317.       CheckMenuItem ( hwndFrame, FID_SYSMENU, Item->MenuId, Item->Flag ) ;
  1318.  
  1319.       DosSemClear ( &ItemSemaphore ) ;
  1320.  
  1321.       ResizeWindow ( hwnd, &Data->Profile ) ;
  1322.  
  1323.       return ( MRFROMSHORT ( 0 ) ) ;
  1324.     }
  1325.   }
  1326.   DosSemClear ( &ItemSemaphore ) ;
  1327.  
  1328.  /***************************************************************************
  1329.   * Dispatch all other commands through the method table.            *
  1330.   ***************************************************************************/
  1331.  
  1332.   return ( DispatchMessage ( hwnd, SHORT1FROMMP(mp1), mp1, mp2, Methods, sizeof(Methods)/sizeof(Methods[0]), NULL ) ) ;
  1333.  
  1334.   hwnd = hwnd ;  msg = msg ;  mp1 = mp1 ;  mp2 = mp2 ;
  1335. }
  1336.  
  1337. /****************************************************************************
  1338.  *                                        *
  1339.  *    Process Reset Defaults menu command.                    *
  1340.  *                                        *
  1341.  ****************************************************************************/
  1342.  
  1343. static MRESULT APIENTRY ResetDefaults
  1344.   HWND hwnd, 
  1345.   USHORT msg, 
  1346.   MPARAM mp1, 
  1347.   MPARAM mp2
  1348. )
  1349. {
  1350.  /***************************************************************************
  1351.   * Reset all profile data for this program.                    *
  1352.   ***************************************************************************/
  1353.  
  1354.   PrfWriteProfileData ( HINI_USERPROFILE, PROGRAM_NAME, NULL, NULL, 0 ) ;
  1355.  
  1356.  /***************************************************************************
  1357.   * Reset the program's presentation parameters.                            *
  1358.   ***************************************************************************/
  1359.  
  1360.   WinRemovePresParam ( hwnd, PP_FONTNAMESIZE ) ;
  1361.   WinRemovePresParam ( hwnd, PP_FOREGROUNDCOLOR ) ;
  1362.   WinRemovePresParam ( hwnd, PP_BACKGROUNDCOLOR ) ;
  1363.  
  1364.  /***************************************************************************
  1365.   * Done.                                    *
  1366.   ***************************************************************************/
  1367.  
  1368.   return ( MRFROMSHORT ( 0 ) ) ;
  1369.  
  1370.   hwnd = hwnd ;  msg = msg ;  mp1 = mp1 ;  mp2 = mp2 ;
  1371. }
  1372.  
  1373. /****************************************************************************
  1374.  *                                        *
  1375.  *    Process Hide Controls menu command.                    *
  1376.  *                                        *
  1377.  ****************************************************************************/
  1378.  
  1379. static MRESULT APIENTRY HideControlsCmd
  1380.   HWND hwnd, 
  1381.   USHORT msg, 
  1382.   MPARAM mp1, 
  1383.   MPARAM mp2
  1384. )
  1385. {
  1386.  /***************************************************************************
  1387.   * Local Declarations.                             *
  1388.   ***************************************************************************/
  1389.  
  1390.   PDATA Data ;
  1391.   HWND hwndFrame = WinQueryWindow ( hwnd, QW_PARENT, FALSE ) ;
  1392.  
  1393.  /***************************************************************************
  1394.   * Find the instance data.                            *
  1395.   ***************************************************************************/
  1396.  
  1397.   Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1398.  
  1399.  /***************************************************************************
  1400.   * Toggle the Hide Controls setting.                        *
  1401.   ***************************************************************************/
  1402.  
  1403.   Data->Profile.HideControls = Data->Profile.HideControls ? FALSE : TRUE ;
  1404.   Data->Profile.fHideControls = TRUE ;
  1405.  
  1406.  /***************************************************************************
  1407.   * If controls aren't hidden yet, update the menu check-mark.              *
  1408.   ***************************************************************************/
  1409.  
  1410.   if ( Data->Profile.HideControls )
  1411.     CheckMenuItem ( hwndFrame, FID_SYSMENU, IDM_HIDE_CONTROLS, Data->Profile.HideControls ) ;
  1412.  
  1413.  /***************************************************************************
  1414.   * If not minimized right now, hide or reveal the controls.            *
  1415.   ***************************************************************************/
  1416.  
  1417.   if ( NOT ( Data->Profile.Position.fs & SWP_MINIMIZE ) )
  1418.   {
  1419.     HideControls
  1420.     (
  1421.       Data->Profile.HideControls,
  1422.       hwndFrame,
  1423.       Data->hwndSysMenu,
  1424.       Data->hwndTitleBar,
  1425.       Data->hwndMinMax
  1426.     ) ;
  1427.   }
  1428.  
  1429.  /***************************************************************************
  1430.   * If controls are no longer hidden, update the menu check-mark.        *
  1431.   ***************************************************************************/
  1432.  
  1433.   if ( NOT Data->Profile.HideControls )
  1434.     CheckMenuItem ( hwndFrame, FID_SYSMENU, IDM_HIDE_CONTROLS, Data->Profile.HideControls ) ;
  1435.  
  1436.  /***************************************************************************
  1437.   * Done.                                    *
  1438.   ***************************************************************************/
  1439.  
  1440.   return ( MRFROMSHORT ( 0 ) ) ;
  1441.  
  1442.   hwnd = hwnd ;  msg = msg ;  mp1 = mp1 ;  mp2 = mp2 ;
  1443. }
  1444.  
  1445. /****************************************************************************
  1446.  *                                        *
  1447.  *    Process Set Timer menu command.                     *
  1448.  *                                        *
  1449.  ****************************************************************************/
  1450.  
  1451. static MRESULT APIENTRY SetTimer
  1452.   HWND hwnd, 
  1453.   USHORT msg, 
  1454.   MPARAM mp1, 
  1455.   MPARAM mp2
  1456. )
  1457. {
  1458.  /***************************************************************************
  1459.   * Local Declarations.                             *
  1460.   ***************************************************************************/
  1461.  
  1462.   PDATA Data ;
  1463.   SETTIMER_PARMS Parms ;
  1464.  
  1465.  /***************************************************************************
  1466.   * Find the instance data.                            *
  1467.   ***************************************************************************/
  1468.  
  1469.   Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1470.  
  1471.  /***************************************************************************
  1472.   * Invoke the Set Timer dialog.                        *
  1473.   ***************************************************************************/
  1474.  
  1475.   Parms.id = IDD_SET_TIMER ;
  1476.   Parms.hwndHelp = WinQueryHelpInstance ( hwnd ) ;
  1477.   Parms.TimerInterval = & Data->Profile.TimerInterval ;
  1478.  
  1479.   WinDlgBox ( HWND_DESKTOP, hwnd, SetTimerProcessor,
  1480.     Data->Library, IDD_SET_TIMER, &Parms ) ;
  1481.  
  1482.  /***************************************************************************
  1483.   * Done.                                    *
  1484.   ***************************************************************************/
  1485.  
  1486.   return ( MRFROMSHORT ( 0 ) ) ;
  1487.  
  1488.   hwnd = hwnd ;  msg = msg ;  mp1 = mp1 ;  mp2 = mp2 ;
  1489. }
  1490.  
  1491. /****************************************************************************
  1492.  *                                        *
  1493.  *    Process About menu command.                        *
  1494.  *                                        *
  1495.  ****************************************************************************/
  1496.  
  1497. static MRESULT APIENTRY About
  1498.   HWND hwnd, 
  1499.   USHORT msg, 
  1500.   MPARAM mp1, 
  1501.   MPARAM mp2
  1502. )
  1503. {
  1504.  /***************************************************************************
  1505.   * Local Declarations                                *
  1506.   ***************************************************************************/
  1507.  
  1508.   PDATA Data ;
  1509.   ABOUT_PARMS Parms ;
  1510.  
  1511.  /***************************************************************************
  1512.   * Find the instance data.                            *
  1513.   ***************************************************************************/
  1514.  
  1515.   Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1516.  
  1517.  /***************************************************************************
  1518.   * Invoke the About dialog.                            *
  1519.   ***************************************************************************/
  1520.  
  1521.   Parms.id = IDD_ABOUT ;
  1522.   Parms.hwndHelp = WinQueryHelpInstance ( hwnd ) ;
  1523.  
  1524.   WinDlgBox ( HWND_DESKTOP, hwnd, AboutProcessor,
  1525.     Data->Library, IDD_ABOUT, &Parms ) ;
  1526.  
  1527.  /***************************************************************************
  1528.   * Done.                                    *
  1529.   ***************************************************************************/
  1530.  
  1531.   return ( MRFROMSHORT ( 0 ) ) ;
  1532.  
  1533.   hwnd = hwnd ;  msg = msg ;  mp1 = mp1 ;  mp2 = mp2 ;
  1534. }
  1535.  
  1536. /****************************************************************************
  1537.  *                                        *
  1538.  *    Process Mouse Button being pressed.                    *
  1539.  *                                        *
  1540.  ****************************************************************************/
  1541.  
  1542. static MRESULT APIENTRY ButtonDown
  1543. (
  1544.   HWND hwnd,
  1545.   USHORT msg,
  1546.   MPARAM mp1,
  1547.   MPARAM mp2
  1548. )
  1549. {
  1550.  /***************************************************************************
  1551.   * Local Declarations                                *
  1552.   ***************************************************************************/
  1553.  
  1554.   PDATA Data ;
  1555.   HWND hwndFrame ;
  1556.   SWP Position ;
  1557.   TRACKINFO TrackInfo ;
  1558.  
  1559.  /***************************************************************************
  1560.   * Find the instance data.                            *
  1561.   ***************************************************************************/
  1562.  
  1563.   Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1564.  
  1565.  /***************************************************************************
  1566.   * Determine the new window position.                        *
  1567.   ***************************************************************************/
  1568.  
  1569.   memset ( &TrackInfo, 0, sizeof(TrackInfo) ) ;
  1570.  
  1571.   TrackInfo.cxBorder = 1 ;
  1572.   TrackInfo.cyBorder = 1 ;
  1573.   TrackInfo.cxGrid = 1 ;
  1574.   TrackInfo.cyGrid = 1 ;
  1575.   TrackInfo.cxKeyboard = 8 ;
  1576.   TrackInfo.cyKeyboard = 8 ;
  1577.  
  1578.   hwndFrame = WinQueryWindow ( hwnd, QW_PARENT, FALSE ) ;
  1579.  
  1580.   WinQueryWindowPos ( hwndFrame, &Position ) ;
  1581.   TrackInfo.rclTrack.xLeft   = Position.x ;
  1582.   TrackInfo.rclTrack.xRight  = Position.x + Position.cx ;
  1583.   TrackInfo.rclTrack.yBottom = Position.y ;
  1584.   TrackInfo.rclTrack.yTop    = Position.y + Position.cy ;
  1585.  
  1586.   WinQueryWindowPos ( HWND_DESKTOP, &Position ) ;
  1587.   TrackInfo.rclBoundary.xLeft   = Position.x ;
  1588.   TrackInfo.rclBoundary.xRight  = Position.x + Position.cx ;
  1589.   TrackInfo.rclBoundary.yBottom = Position.y ;
  1590.   TrackInfo.rclBoundary.yTop    = Position.y + Position.cy ;
  1591.  
  1592.   TrackInfo.ptlMinTrackSize.x = 0 ;
  1593.   TrackInfo.ptlMinTrackSize.y = 0 ;
  1594.   TrackInfo.ptlMaxTrackSize.x = Position.cx ;
  1595.   TrackInfo.ptlMaxTrackSize.y = Position.cy ;
  1596.  
  1597.   TrackInfo.fs = TF_MOVE | TF_STANDARD | TF_ALLINBOUNDARY ;
  1598.  
  1599.   if ( WinTrackRect ( HWND_DESKTOP, NULL, &TrackInfo ) )
  1600.   {
  1601.     WinSetWindowPos ( hwndFrame, NULL,
  1602.       (SHORT) TrackInfo.rclTrack.xLeft,
  1603.       (SHORT) TrackInfo.rclTrack.yBottom,
  1604.       0, 0, SWP_MOVE ) ;
  1605.   }
  1606.  
  1607.  /***************************************************************************
  1608.   * Return through the default processor, letting window activation        *
  1609.   *   and other system functions occur.                     *
  1610.   ***************************************************************************/
  1611.  
  1612.   return ( WinDefWindowProc ( hwnd, msg, mp1, mp2 ) ) ;
  1613.  
  1614.   hwnd = hwnd ;  msg = msg ;  mp1 = mp1 ;  mp2 = mp2 ;
  1615. }
  1616.  
  1617. /****************************************************************************
  1618.  *                                        *
  1619.  *    Process Mouse Button having been double-clicked.            *
  1620.  *                                        *
  1621.  ****************************************************************************/
  1622.  
  1623. static MRESULT APIENTRY ButtonDblClick
  1624. (
  1625.   HWND hwnd,
  1626.   USHORT msg,
  1627.   MPARAM mp1,
  1628.   MPARAM mp2
  1629. )
  1630. {
  1631.  /***************************************************************************
  1632.   * Send message to self to stop hiding the controls.                *
  1633.   ***************************************************************************/
  1634.  
  1635.   WinPostMsg ( hwnd, WM_COMMAND,
  1636.     MPFROM2SHORT ( IDM_HIDE_CONTROLS, 0 ),
  1637.     MPFROM2SHORT ( CMDSRC_OTHER, TRUE ) ) ;
  1638.  
  1639.  /***************************************************************************
  1640.   * Return through the default processor, letting window activation        *
  1641.   *   and other system functions occur.                     *
  1642.   ***************************************************************************/
  1643.  
  1644.   return ( WinDefWindowProc ( hwnd, msg, mp1, mp2 ) ) ;
  1645.  
  1646.   hwnd = hwnd ;  msg = msg ;  mp1 = mp1 ;  mp2 = mp2 ;
  1647. }
  1648.  
  1649. /****************************************************************************
  1650.  *                                        *
  1651.  *    Process Presentation Parameter Changed notification.            *
  1652.  *                                        *
  1653.  ****************************************************************************/
  1654.  
  1655. static MRESULT APIENTRY PresParamChanged
  1656. (
  1657.   HWND hwnd,
  1658.   USHORT msg,
  1659.   MPARAM mp1,
  1660.   MPARAM mp2
  1661. )
  1662. {
  1663.  /***************************************************************************
  1664.   * Local Declarations                                *
  1665.   ***************************************************************************/
  1666.  
  1667.   PDATA Data ;
  1668.   HPS hPS ;
  1669.   ULONG ppid ;
  1670.   RECTL Rectangle ;
  1671.  
  1672.  /***************************************************************************
  1673.   * Find the instance data.                            *
  1674.   ***************************************************************************/
  1675.  
  1676.   Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1677.  
  1678.  /***************************************************************************
  1679.   * Get the presentation parameter that changed.                *
  1680.   ***************************************************************************/
  1681.  
  1682.   switch ( LONGFROMMP(mp1) )
  1683.   {
  1684.  
  1685.    /*************************************************************************
  1686.     * If font, note the fact that we now have a font to be saved as        *
  1687.     *    part of the configuration.  Get the font metrics and resize        *
  1688.     *    the window appropriately.                        *
  1689.     *************************************************************************/
  1690.  
  1691.     case PP_FONTNAMESIZE:
  1692.     {
  1693.       if ( WinQueryPresParam ( hwnd, PP_FONTNAMESIZE, 0, &ppid,
  1694.     sizeof(Data->Profile.FontNameSize), &Data->Profile.FontNameSize,
  1695.     0 ) )
  1696.       {
  1697.     Data->Profile.fFontNameSize = TRUE ;
  1698.       }
  1699.       else
  1700.       {
  1701.     strcpy ( Data->Profile.FontNameSize, "" ) ;
  1702.     Data->Profile.fFontNameSize = FALSE ;
  1703.     PrfWriteProfileData ( HINI_USERPROFILE, PROGRAM_NAME, "FontNameSize", NULL, 0 ) ;
  1704.       }
  1705.  
  1706.       hPS = WinGetPS ( hwnd ) ;
  1707.       WinQueryWindowRect ( HWND_DESKTOP, &Rectangle ) ;
  1708.       WinDrawText ( hPS, 1, " ", &Rectangle, 0L, 0L, DT_LEFT | DT_BOTTOM | DT_QUERYEXTENT ) ;
  1709.       Data->Width  = Rectangle.xRight - Rectangle.xLeft ;
  1710.       Data->Height = Rectangle.yTop - Rectangle.yBottom ;
  1711.       WinReleasePS ( hPS ) ;
  1712.       ResizeWindow ( hwnd, &Data->Profile ) ;
  1713.       break ;
  1714.     }
  1715.  
  1716.    /*************************************************************************
  1717.     * If background color, note the fact and repaint the window.        *
  1718.     *************************************************************************/
  1719.  
  1720.     case PP_BACKGROUNDCOLOR:
  1721.     {
  1722.       if ( WinQueryPresParam ( hwnd, PP_BACKGROUNDCOLOR, 0, &ppid,
  1723.     sizeof(Data->Profile.BackColor), &Data->Profile.BackColor, 0 ) )
  1724.       {
  1725.     Data->Profile.fBackColor = TRUE ;
  1726.       }
  1727.       else
  1728.       {
  1729.     Data->Profile.BackColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_WINDOW, 0L ) ;
  1730.     Data->Profile.fBackColor = FALSE ;
  1731.     PrfWriteProfileData ( HINI_USERPROFILE, PROGRAM_NAME, "BackgroundColor", NULL, 0 ) ;
  1732.       }
  1733.       WinInvalidateRect ( hwnd, NULL, TRUE ) ;
  1734.       break ;
  1735.     }
  1736.  
  1737.    /*************************************************************************
  1738.     * If foreground color, note the fact and repaint the window.        *
  1739.     *************************************************************************/
  1740.  
  1741.     case PP_FOREGROUNDCOLOR:
  1742.     {
  1743.       if ( WinQueryPresParam ( hwnd, PP_FOREGROUNDCOLOR, 0, &ppid,
  1744.     sizeof(Data->Profile.TextColor), &Data->Profile.TextColor, 0 ) )
  1745.       {
  1746.     Data->Profile.fTextColor = TRUE ;
  1747.       }
  1748.       else
  1749.       {
  1750.     Data->Profile.TextColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_OUTPUTTEXT, 0L ) ;
  1751.     Data->Profile.fTextColor = FALSE ;
  1752.     PrfWriteProfileData ( HINI_USERPROFILE, PROGRAM_NAME, "ForegroundColor", NULL, 0 ) ;
  1753.       }
  1754.       WinInvalidateRect ( hwnd, NULL, TRUE ) ;
  1755.       break ;
  1756.     }
  1757.   }
  1758.  
  1759.  /***************************************************************************
  1760.   * Return through the default processor, letting window activation        *
  1761.   *   and other system functions occur.                     *
  1762.   ***************************************************************************/
  1763.  
  1764.   return ( WinDefWindowProc ( hwnd, msg, mp1, mp2 ) ) ;
  1765.  
  1766.   hwnd = hwnd ;  msg = msg ;  mp1 = mp1 ;  mp2 = mp2 ;
  1767. }
  1768.  
  1769. /****************************************************************************
  1770.  *                                        *
  1771.  *    Process System Color Change notification.                *
  1772.  *                                        *
  1773.  ****************************************************************************/
  1774.  
  1775. static MRESULT APIENTRY SysColorChange
  1776. (
  1777.   HWND hwnd,
  1778.   USHORT msg,
  1779.   MPARAM mp1,
  1780.   MPARAM mp2
  1781. )
  1782. {
  1783.  /***************************************************************************
  1784.   * Local Declarations                                *
  1785.   ***************************************************************************/
  1786.  
  1787.   PDATA Data ;
  1788.  
  1789.  /***************************************************************************
  1790.   * Find the instance data.                            *
  1791.   ***************************************************************************/
  1792.  
  1793.   Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1794.  
  1795.  /***************************************************************************
  1796.   * If we aren't using custom colors, then query for the new defaults.      *
  1797.   ***************************************************************************/
  1798.  
  1799.   if ( NOT Data->Profile.fBackColor )
  1800.   {
  1801.     Data->Profile.BackColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_WINDOW, 0L ) ;
  1802.   }
  1803.  
  1804.   if ( NOT Data->Profile.fTextColor )
  1805.   {
  1806.     Data->Profile.TextColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_OUTPUTTEXT, 0L ) ;
  1807.   }
  1808.  
  1809.  /***************************************************************************
  1810.   * Return value must be NULL, according to the documentation.            *
  1811.   ***************************************************************************/
  1812.  
  1813.   return ( MRFROMP ( NULL ) ) ;
  1814.  
  1815.   hwnd = hwnd ;  msg = msg ;  mp1 = mp1 ;  mp2 = mp2 ;
  1816. }
  1817.  
  1818. /****************************************************************************
  1819.  *                                        *
  1820.  *    Process Query for Keys Help resource id.                *
  1821.  *                                        *
  1822.  ****************************************************************************/
  1823.  
  1824. static MRESULT APIENTRY QueryKeysHelp
  1825. (
  1826.   HWND hwnd,
  1827.   USHORT msg,
  1828.   MPARAM mp1,
  1829.   MPARAM mp2
  1830. )
  1831. {
  1832.  /***************************************************************************
  1833.   * Simply return the ID of the Keys Help panel.                *
  1834.   ***************************************************************************/
  1835.  
  1836.   return ( (MRESULT) IDM_KEYS_HELP ) ;
  1837.  
  1838.   hwnd = hwnd ;  msg = msg ;  mp1 = mp1 ;  mp2 = mp2 ;
  1839. }
  1840.  
  1841. /****************************************************************************
  1842.  *                                        *
  1843.  *    Process Help Manager Error                        *
  1844.  *                                        *
  1845.  ****************************************************************************/
  1846.  
  1847. static MRESULT APIENTRY HelpError
  1848.   HWND hwnd, 
  1849.   USHORT msg, 
  1850.   MPARAM mp1, 
  1851.   MPARAM mp2
  1852. )
  1853. {
  1854.  /***************************************************************************
  1855.   * Local Declarations                                *
  1856.   ***************************************************************************/
  1857.  
  1858.   static struct
  1859.   {
  1860.     ULONG Error ;
  1861.     USHORT StringId ;
  1862.   }
  1863.   HelpErrors [] =
  1864.   {
  1865.     { HMERR_NO_FRAME_WND_IN_CHAIN,     IDS_HMERR_NO_FRAME_WND_IN_CHAIN },
  1866.     { HMERR_INVALID_ASSOC_APP_WND,     IDS_HMERR_INVALID_ASSOC_APP_WND },
  1867.     { HMERR_INVALID_ASSOC_HELP_INST,   IDS_HMERR_INVALID_ASSOC_HELP_IN },
  1868.     { HMERR_INVALID_DESTROY_HELP_INST, IDS_HMERR_INVALID_DESTROY_HELP_ },
  1869.     { HMERR_NO_HELP_INST_IN_CHAIN,     IDS_HMERR_NO_HELP_INST_IN_CHAIN },
  1870.     { HMERR_INVALID_HELP_INSTANCE_HDL, IDS_HMERR_INVALID_HELP_INSTANCE },
  1871.     { HMERR_INVALID_QUERY_APP_WND,     IDS_HMERR_INVALID_QUERY_APP_WND },
  1872.     { HMERR_HELP_INST_CALLED_INVALID,  IDS_HMERR_HELP_INST_CALLED_INVA },
  1873.     { HMERR_HELPTABLE_UNDEFINE,        IDS_HMERR_HELPTABLE_UNDEFINE    },
  1874.     { HMERR_HELP_INSTANCE_UNDEFINE,    IDS_HMERR_HELP_INSTANCE_UNDEFIN },
  1875.     { HMERR_HELPITEM_NOT_FOUND,        IDS_HMERR_HELPITEM_NOT_FOUND    },
  1876.     { HMERR_INVALID_HELPSUBITEM_SIZE,  IDS_HMERR_INVALID_HELPSUBITEM_S },
  1877.     { HMERR_HELPSUBITEM_NOT_FOUND,     IDS_HMERR_HELPSUBITEM_NOT_FOUND },
  1878.     { HMERR_INDEX_NOT_FOUND,           IDS_HMERR_INDEX_NOT_FOUND       },
  1879.     { HMERR_CONTENT_NOT_FOUND,           IDS_HMERR_CONTENT_NOT_FOUND     },
  1880.     { HMERR_OPEN_LIB_FILE,           IDS_HMERR_OPEN_LIB_FILE           },
  1881.     { HMERR_READ_LIB_FILE,           IDS_HMERR_READ_LIB_FILE           },
  1882.     { HMERR_CLOSE_LIB_FILE,           IDS_HMERR_CLOSE_LIB_FILE        },
  1883.     { HMERR_INVALID_LIB_FILE,           IDS_HMERR_INVALID_LIB_FILE      },
  1884.     { HMERR_NO_MEMORY,               IDS_HMERR_NO_MEMORY           },
  1885.     { HMERR_ALLOCATE_SEGMENT,           IDS_HMERR_ALLOCATE_SEGMENT      },
  1886.     { HMERR_FREE_MEMORY,           IDS_HMERR_FREE_MEMORY           },
  1887.     { HMERR_PANEL_NOT_FOUND,           IDS_HMERR_PANEL_NOT_FOUND       },
  1888.     { HMERR_DATABASE_NOT_OPEN,           IDS_HMERR_DATABASE_NOT_OPEN     },
  1889.     { 0,                   IDS_HMERR_UNKNOWN           }
  1890.   } ;
  1891.  
  1892.   PDATA Data ;
  1893.   ULONG ErrorCode = (ULONG) LONGFROMMP ( mp1 ) ;
  1894.   int Index ;
  1895.   char Message [200] ;
  1896.   char Title [80] ;
  1897.  
  1898.  /***************************************************************************
  1899.   * Find the instance data.                            *
  1900.   ***************************************************************************/
  1901.  
  1902.   Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1903.  
  1904.  /***************************************************************************
  1905.   * Find the error code in the message table.                    *
  1906.   ***************************************************************************/
  1907.  
  1908.   Index = 0 ;
  1909.   while ( HelpErrors[Index].Error
  1910.     AND ( HelpErrors[Index].Error != ErrorCode ) )
  1911.   {
  1912.     Index ++ ;
  1913.   }
  1914.  
  1915.  /***************************************************************************
  1916.   * Get the message texts.                            *
  1917.   ***************************************************************************/
  1918.  
  1919.   WinLoadString ( Data->Anchor, Data->Library, IDS_HMERR, sizeof(Title), Title ) ;
  1920.  
  1921.   WinLoadString ( Data->Anchor, Data->Library, HelpErrors[Index].StringId, sizeof(Message), Message ) ;
  1922.  
  1923.  /***************************************************************************
  1924.   * Display the error message.                            *
  1925.   ***************************************************************************/
  1926.  
  1927.   WinMessageBox
  1928.   (
  1929.     HWND_DESKTOP,
  1930.     hwnd,
  1931.     Message,
  1932.     Title,
  1933.     0,
  1934.     MB_OK | MB_WARNING
  1935.   ) ;
  1936.  
  1937.  /***************************************************************************
  1938.   * Return zero, indicating that the message was processed.            *
  1939.   ***************************************************************************/
  1940.  
  1941.   return ( MRFROMSHORT ( 0 ) ) ;
  1942.  
  1943.   hwnd = hwnd ;  msg = msg ;  mp1 = mp1 ;  mp2 = mp2 ;
  1944. }
  1945.  
  1946. /****************************************************************************
  1947.  *                                        *
  1948.  *    Process "Extended Help Undefined" notification                *
  1949.  *                                        *
  1950.  ****************************************************************************/
  1951.  
  1952. static MRESULT APIENTRY ExtHelpUndefined
  1953.   HWND hwnd, 
  1954.   USHORT msg, 
  1955.   MPARAM mp1, 
  1956.   MPARAM mp2
  1957. )
  1958. {
  1959.  /***************************************************************************
  1960.   * Local Declarations                                *
  1961.   ***************************************************************************/
  1962.  
  1963.   PDATA Data ;
  1964.   char Message [200] ;
  1965.   char Title [80] ;
  1966.  
  1967.  /***************************************************************************
  1968.   * Find the instance data.                            *
  1969.   ***************************************************************************/
  1970.  
  1971.   Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1972.  
  1973.  /***************************************************************************
  1974.   * Get the message texts.                            *
  1975.   ***************************************************************************/
  1976.  
  1977.   WinLoadString ( Data->Anchor, Data->Library, IDS_HMERR, sizeof(Title), Title ) ;
  1978.  
  1979.   WinLoadString ( Data->Anchor, Data->Library, IDS_HMERR_EXTHELPUNDEFINED, sizeof(Message), Message ) ;
  1980.  
  1981.  /***************************************************************************
  1982.   * Display the error message.                            *
  1983.   ***************************************************************************/
  1984.  
  1985.   WinMessageBox
  1986.   (
  1987.     HWND_DESKTOP,
  1988.     hwnd,
  1989.     Message,
  1990.     Title,
  1991.     0,
  1992.     MB_OK | MB_WARNING
  1993.   ) ;
  1994.  
  1995.  /***************************************************************************
  1996.   * Return zero, indicating that the message was processed.            *
  1997.   ***************************************************************************/
  1998.  
  1999.   return ( MRFROMSHORT ( 0 ) ) ;
  2000.  
  2001.   hwnd = hwnd ;  msg = msg ;  mp1 = mp1 ;  mp2 = mp2 ;
  2002. }
  2003.  
  2004. /****************************************************************************
  2005.  *                                        *
  2006.  *    Process "Help Subitem Not Found" notification                *
  2007.  *                                        *
  2008.  ****************************************************************************/
  2009.  
  2010. static MRESULT APIENTRY HelpSubitemNotFound
  2011.   HWND hwnd, 
  2012.   USHORT msg, 
  2013.   MPARAM mp1, 
  2014.   MPARAM mp2
  2015. )
  2016. {
  2017.  /***************************************************************************
  2018.   * Local Declarations                                *
  2019.   ***************************************************************************/
  2020.  
  2021.   PDATA Data ;
  2022.   int i ;
  2023.   BYTE Format [200] ;
  2024.   BYTE Message [200] ;
  2025.   BYTE Mode [40] ;
  2026.   USHORT Subtopic ;
  2027.   char Title [80] ;
  2028.   USHORT Topic ;
  2029.  
  2030.  /***************************************************************************
  2031.   * Find the instance data.                            *
  2032.   ***************************************************************************/
  2033.  
  2034.   Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  2035.  
  2036.  /***************************************************************************
  2037.   * Get the title text.                             *
  2038.   ***************************************************************************/
  2039.  
  2040.   WinLoadString ( Data->Anchor, Data->Library, IDS_HMERR, sizeof(Title), Title ) ;
  2041.  
  2042.  /***************************************************************************
  2043.   * Format the error message.                            *
  2044.   ***************************************************************************/
  2045.  
  2046.   Topic = (USHORT) SHORT1FROMMP ( mp2 ) ;
  2047.   Subtopic = (USHORT) SHORT2FROMMP ( mp2 ) ;
  2048.  
  2049.   i = SHORT1FROMMP ( mp1 ) ;
  2050.  
  2051.   switch ( i )
  2052.   {
  2053.     case HLPM_FRAME:
  2054.       WinLoadString ( Data->Anchor, Data->Library, IDS_HELPMODE_FRAME, sizeof(Mode), Mode ) ;
  2055.       break ;
  2056.  
  2057.     case HLPM_MENU:
  2058.       WinLoadString ( Data->Anchor, Data->Library, IDS_HELPMODE_MENU, sizeof(Mode), Mode ) ;
  2059.       break ;
  2060.  
  2061.     case HLPM_WINDOW:
  2062.       WinLoadString ( Data->Anchor, Data->Library, IDS_HELPMODE_WINDOW, sizeof(Mode), Mode ) ;
  2063.       break ;
  2064.  
  2065.     default:
  2066.       WinLoadString ( Data->Anchor, Data->Library, IDS_HELPMODE_UNKNOWN, sizeof(Mode), Mode ) ;
  2067.   }
  2068.  
  2069.   WinLoadString ( Data->Anchor, Data->Library, IDS_HELPSUBITEMNOTFOUND, sizeof(Format), Format ) ;
  2070.  
  2071.   sprintf ( Message, Format, Mode, Topic, Subtopic ) ;
  2072.  
  2073.  /***************************************************************************
  2074.   * Display the error message.                            *
  2075.   ***************************************************************************/
  2076.  
  2077.   WinMessageBox
  2078.   (
  2079.     HWND_DESKTOP,
  2080.     hwnd,
  2081.     Message,
  2082.     Title,
  2083.     0,
  2084.     MB_OK | MB_WARNING
  2085.   ) ;
  2086.  
  2087.  /***************************************************************************
  2088.   * Return zero, indicating that the message was processed.            *
  2089.   ***************************************************************************/
  2090.  
  2091.   return ( MRFROMSHORT ( 0 ) ) ;
  2092.  
  2093.   hwnd = hwnd ;  msg = msg ;  mp1 = mp1 ;  mp2 = mp2 ;
  2094. }
  2095.  
  2096. /****************************************************************************
  2097.  *                                        *
  2098.  *    Process Refresh message.                        *
  2099.  *                                        *
  2100.  ****************************************************************************/
  2101.  
  2102. static MRESULT APIENTRY Refresh
  2103.   HWND hwnd, 
  2104.   USHORT msg, 
  2105.   MPARAM mp1, 
  2106.   MPARAM mp2
  2107. )
  2108. {
  2109.  /***************************************************************************
  2110.   * Local Declarations                                *
  2111.   ***************************************************************************/
  2112.  
  2113.   PDATA Data ;
  2114.   USHORT Drive ;
  2115.   ULONG Drives ;
  2116.  
  2117.  /***************************************************************************
  2118.   * Find the instance data.                            *
  2119.   ***************************************************************************/
  2120.  
  2121.   Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  2122.  
  2123.  /***************************************************************************
  2124.   * Save the idle counter.                            *
  2125.   ***************************************************************************/
  2126.  
  2127.   Data->IdleCount = LONGFROMMP ( mp1 ) ;
  2128.  
  2129.  /***************************************************************************
  2130.   * Determine if drive mask has changed.                    *
  2131.   ***************************************************************************/
  2132.  
  2133.   DosQCurDisk ( &Drive, &Drives ) ;
  2134.  
  2135.   if ( Drives != Data->Drives )
  2136.   {
  2137.    /*************************************************************************
  2138.     * It has.  First save the display options.                    *
  2139.     *************************************************************************/
  2140.  
  2141.     SaveApplication ( hwnd, WM_SAVEAPPLICATION, 0, 0 ) ;
  2142.  
  2143.    /*************************************************************************
  2144.     * Next, update the drive item list.                     *
  2145.     *************************************************************************/
  2146.  
  2147.     UpdateDriveList ( Data->Anchor, Data->Library, &Data->Profile, Data->Drives, Drives ) ;
  2148.  
  2149.    /*************************************************************************
  2150.     * If the controls are hidden, hide the whole window and reveal the        *
  2151.     *    controls.  Otherwise the menu wouldn't get updated correctly.       *
  2152.     *************************************************************************/
  2153.  
  2154.     if ( Data->Profile.HideControls )
  2155.     {
  2156.       WinShowWindow ( WinQueryWindow(hwnd,QW_PARENT,FALSE), FALSE ) ;
  2157.       HideControls
  2158.       (
  2159.     FALSE,
  2160.     WinQueryWindow ( hwnd, QW_PARENT, FALSE ),
  2161.     Data->hwndSysMenu,
  2162.     Data->hwndTitleBar,
  2163.     Data->hwndMinMax
  2164.       ) ;
  2165.     }
  2166.  
  2167.    /*************************************************************************
  2168.     * Update the menu.                                *
  2169.     *************************************************************************/
  2170.  
  2171.     RebuildDisplayItems ( hwnd, Data ) ;
  2172.  
  2173.    /*************************************************************************
  2174.     * If the controls were supposed to be hidden, hide them once more and   *
  2175.     *    show the window to the world again.                    *
  2176.     *************************************************************************/
  2177.  
  2178.     if ( Data->Profile.HideControls )
  2179.     {
  2180.       HideControls
  2181.       (
  2182.     TRUE,
  2183.     WinQueryWindow ( hwnd, QW_PARENT, FALSE ),
  2184.     Data->hwndSysMenu,
  2185.     Data->hwndTitleBar,
  2186.     Data->hwndMinMax
  2187.       ) ;
  2188.       WinShowWindow ( WinQueryWindow(hwnd,QW_PARENT,FALSE), TRUE ) ;
  2189.     }
  2190.  
  2191.    /*************************************************************************
  2192.     * Save the updated drive mask.                        *
  2193.     *************************************************************************/
  2194.  
  2195.     Data->Drives = Drives ;
  2196.  
  2197.    /*************************************************************************
  2198.     * Resize the window to accommodate the new option list.            *
  2199.     *************************************************************************/
  2200.  
  2201.     ResizeWindow ( hwnd, &Data->Profile ) ;
  2202.   }
  2203.  
  2204.  /***************************************************************************
  2205.   * Update the statistics.                            *
  2206.   ***************************************************************************/
  2207.  
  2208.   UpdateWindow ( hwnd, Data, FALSE ) ;
  2209.  
  2210.  /***************************************************************************
  2211.   * Return zero, indicating that the message was processed.            *
  2212.   ***************************************************************************/
  2213.  
  2214.   return ( MRFROMSHORT ( 0 ) ) ;
  2215.  
  2216.   hwnd = hwnd ;  msg = msg ;  mp1 = mp1 ;  mp2 = mp2 ;
  2217. }
  2218.  
  2219.  
  2220. /****************************************************************************
  2221.  *                                        *
  2222.  *                 Get Profile Data                    *
  2223.  *                                        *
  2224.  ****************************************************************************/
  2225.  
  2226. static void GetProfile ( HAB Anchor, HMODULE Library, PPROFILE Profile )
  2227. {
  2228.  /***************************************************************************
  2229.   * Local Declarations                                *
  2230.   ***************************************************************************/
  2231.  
  2232.   USHORT Drive ;
  2233.   ULONG  Drives ;
  2234.   int     i ;
  2235.   ULONG  Size ;
  2236.  
  2237.  /***************************************************************************
  2238.   * Lock the item list.                             *
  2239.   ***************************************************************************/
  2240.  
  2241.   if ( DosSemRequest ( &ItemSemaphore, 5000 ) )
  2242.   {
  2243.     Log ( "ERROR: Unable to lock item list to build it.\n" ) ;
  2244.     DosSemRequest ( &ItemSemaphore, SEM_INDEFINITE_WAIT ) ;
  2245.   }
  2246.  
  2247.  /***************************************************************************
  2248.   * Build the fixed portion of the item list.                    *
  2249.   ***************************************************************************/
  2250.  
  2251.   for ( i=0; i<ITEM_BASE_COUNT; i++ )
  2252.   {
  2253.     WinLoadString ( Anchor, Library, i*2+IDS_SHOW_CLOCK_LABEL,
  2254.       sizeof(Items[i].Label), Items[i].Label ) ;
  2255.  
  2256.     WinLoadString ( Anchor, Library, i*2+IDS_SHOW_CLOCK_OPTION,
  2257.       sizeof(Items[i].MenuOption), Items[i].MenuOption ) ;
  2258.  
  2259.     Items[i].Flag = TRUE ;
  2260.     if
  2261.     (
  2262.       PrfQueryProfileSize ( HINI_PROFILE, PROGRAM_NAME, Items[i].Name, &Size )
  2263.       AND
  2264.       ( Size == sizeof(Items[i].Flag) )
  2265.       AND
  2266.       PrfQueryProfileData ( HINI_PROFILE, PROGRAM_NAME, Items[i].Name, &Items[i].Flag, &Size )
  2267.     )
  2268.     {
  2269.       ;
  2270.     }
  2271.   }
  2272.  
  2273.  /***************************************************************************
  2274.   * Release the item list.                            *
  2275.   ***************************************************************************/
  2276.  
  2277.   DosSemClear ( &ItemSemaphore ) ;
  2278.  
  2279.  /***************************************************************************
  2280.   * Add items for each drive on the system.                    *
  2281.   ***************************************************************************/
  2282.  
  2283.   DosQCurDisk ( &Drive, &Drives ) ;
  2284.   UpdateDriveList ( Anchor, Library, Profile, 0, Drives ) ;
  2285.  
  2286.  /***************************************************************************
  2287.   * Get the window's current size and position.                             *
  2288.   ***************************************************************************/
  2289.  
  2290.   memset ( &Profile->Position, 0, sizeof(Profile->Position) ) ;
  2291.   Profile->fPosition = FALSE ;
  2292.   if
  2293.   (
  2294.     PrfQueryProfileSize ( HINI_PROFILE, PROGRAM_NAME, "Position", &Size )
  2295.     AND
  2296.     ( Size == sizeof(Profile->Position) )
  2297.     AND
  2298.     PrfQueryProfileData ( HINI_PROFILE, PROGRAM_NAME, "Position", &Profile->Position, &Size )
  2299.   )
  2300.   {
  2301.     Profile->fPosition = TRUE ;
  2302.   }
  2303.  
  2304.  /***************************************************************************
  2305.   * Get the program options.                            *
  2306.   ***************************************************************************/
  2307.  
  2308.   Profile->HideControls = FALSE ;
  2309.   if
  2310.   (
  2311.     PrfQueryProfileSize ( HINI_PROFILE, PROGRAM_NAME, "HideControls", &Size )
  2312.     AND
  2313.     ( Size == sizeof(Profile->HideControls) )
  2314.     AND
  2315.     PrfQueryProfileData ( HINI_PROFILE, PROGRAM_NAME, "HideControls", &Profile->HideControls, &Size )
  2316.   )
  2317.   {
  2318.     Profile->fHideControls = TRUE ;
  2319.   }
  2320.  
  2321.   Profile->TimerInterval = 1000 ;
  2322.   if
  2323.   (
  2324.     PrfQueryProfileSize ( HINI_PROFILE, PROGRAM_NAME, "TimerInterval", &Size )
  2325.     AND
  2326.     ( Size == sizeof(Profile->TimerInterval) )
  2327.     AND
  2328.     PrfQueryProfileData ( HINI_PROFILE, PROGRAM_NAME, "TimerInterval", &Profile->TimerInterval, &Size )
  2329.   )
  2330.   {
  2331.     Profile->fTimerInterval = TRUE ;
  2332.   }
  2333.  
  2334.  /***************************************************************************
  2335.   * Get the presentation parameters.                        *
  2336.   ***************************************************************************/
  2337.  
  2338.   strcpy ( Profile->FontNameSize, "" ) ;
  2339.   Profile->fFontNameSize = FALSE ;
  2340.   if
  2341.   (
  2342.     PrfQueryProfileSize ( HINI_PROFILE, PROGRAM_NAME, "FontNameSize", &Size )
  2343.     AND
  2344.     ( Size == sizeof(Profile->FontNameSize) )
  2345.     AND
  2346.     PrfQueryProfileData ( HINI_PROFILE, PROGRAM_NAME, "FontNameSize", &Profile->FontNameSize, &Size )
  2347.   )
  2348.   {
  2349.     Profile->fFontNameSize = TRUE ;
  2350.   }
  2351.  
  2352.   Profile->BackColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_WINDOW, 0L ) ;
  2353.   Profile->fBackColor = FALSE ;
  2354.   if
  2355.   (
  2356.     PrfQueryProfileSize ( HINI_PROFILE, PROGRAM_NAME, "BackgroundColor", &Size )
  2357.     AND
  2358.     ( Size == sizeof(Profile->BackColor) )
  2359.     AND
  2360.     PrfQueryProfileData ( HINI_PROFILE, PROGRAM_NAME, "BackgroundColor", &Profile->BackColor, &Size )
  2361.   )
  2362.   {
  2363.     Profile->fBackColor = TRUE ;
  2364.   }
  2365.  
  2366.   Profile->TextColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_OUTPUTTEXT, 0L ) ;
  2367.   Profile->fTextColor = FALSE ;
  2368.   if
  2369.   (
  2370.     PrfQueryProfileSize ( HINI_PROFILE, PROGRAM_NAME, "ForegroundColor", &Size )
  2371.     AND
  2372.     ( Size == sizeof(Profile->TextColor) )
  2373.     AND
  2374.     PrfQueryProfileData ( HINI_PROFILE, PROGRAM_NAME, "ForegroundColor", &Profile->TextColor, &Size )
  2375.   )
  2376.   {
  2377.     Profile->fTextColor = TRUE ;
  2378.   }
  2379. }
  2380.  
  2381. /****************************************************************************
  2382.  *                                        *
  2383.  *                 Put Profile Data                    *
  2384.  *                                        *
  2385.  ****************************************************************************/
  2386.  
  2387. static void PutProfile ( PPROFILE Profile )
  2388. {
  2389.  /***************************************************************************
  2390.   * Local Declarations                                *
  2391.   ***************************************************************************/
  2392.  
  2393.   int i ;
  2394.  
  2395.  /***************************************************************************
  2396.   * Save the window's current size and position.                            *
  2397.   ***************************************************************************/
  2398.  
  2399.   PrfWriteProfileData
  2400.   (
  2401.     HINI_USERPROFILE,
  2402.     PROGRAM_NAME,
  2403.     "Position",
  2404.     &Profile->Position,
  2405.     (ULONG)sizeof(Profile->Position)
  2406.   ) ;
  2407.  
  2408.  /***************************************************************************
  2409.   * Save the program options.                            *
  2410.   ***************************************************************************/
  2411.  
  2412.   if ( Profile->fHideControls )
  2413.   {
  2414.     PrfWriteProfileData
  2415.     (
  2416.       HINI_USERPROFILE,
  2417.       PROGRAM_NAME,
  2418.       "HideControls",
  2419.       &Profile->HideControls,
  2420.       (ULONG)sizeof(Profile->HideControls)
  2421.     ) ;
  2422.   }
  2423.  
  2424.   if ( Profile->fTimerInterval )
  2425.   {
  2426.     PrfWriteProfileData
  2427.     (
  2428.       HINI_USERPROFILE,
  2429.       PROGRAM_NAME,
  2430.       "TimerInterval",
  2431.       &Profile->TimerInterval,
  2432.       (ULONG)sizeof(Profile->TimerInterval)
  2433.     ) ;
  2434.   }
  2435.  
  2436.  /***************************************************************************
  2437.   * Save the item options.                            *
  2438.   ***************************************************************************/
  2439.  
  2440.   if ( DosSemRequest ( &ItemSemaphore, 5000 ) )
  2441.   {
  2442.     Log ( "ERROR: Unable to lock item list to save display options.\n" ) ;
  2443.     DosSemRequest ( &ItemSemaphore, SEM_INDEFINITE_WAIT ) ;
  2444.   }
  2445.   for ( i=0; i<Profile->ItemCount; i++ )
  2446.   {
  2447.     PITEM Item = & Profile->Items [i] ;
  2448.  
  2449.     PrfWriteProfileData
  2450.     (
  2451.       HINI_USERPROFILE,
  2452.       PROGRAM_NAME,
  2453.       Item->Name,
  2454.       &Item->Flag,
  2455.       (ULONG)sizeof(Item->Flag)
  2456.     ) ;
  2457.   }
  2458.   DosSemClear ( &ItemSemaphore ) ;
  2459.  
  2460.  /***************************************************************************
  2461.   * Save the presentation parameters.                        *
  2462.   ***************************************************************************/
  2463.  
  2464.   if ( Profile->fFontNameSize )
  2465.   {
  2466.     PrfWriteProfileData
  2467.     (
  2468.       HINI_USERPROFILE,
  2469.       PROGRAM_NAME,
  2470.       "FontNameSize",
  2471.       Profile->FontNameSize,
  2472.       (ULONG)sizeof(Profile->FontNameSize)
  2473.     ) ;
  2474.   }
  2475.  
  2476.   if ( Profile->fBackColor )
  2477.   {
  2478.     PrfWriteProfileData
  2479.     (
  2480.       HINI_USERPROFILE,
  2481.       PROGRAM_NAME,
  2482.       "BackgroundColor",
  2483.       &Profile->BackColor,
  2484.       (ULONG)sizeof(Profile->BackColor)
  2485.     ) ;
  2486.   }
  2487.  
  2488.   if ( Profile->fTextColor )
  2489.   {
  2490.     PrfWriteProfileData
  2491.     (
  2492.       HINI_USERPROFILE,
  2493.       PROGRAM_NAME,
  2494.       "ForegroundColor",
  2495.       &Profile->TextColor,
  2496.       (ULONG)sizeof(Profile->TextColor)
  2497.     ) ;
  2498.   }
  2499. }
  2500.  
  2501. /****************************************************************************
  2502.  *                                        *
  2503.  *    Scan CONFIG.SYS for a keyword.    Return the value.            *
  2504.  *                                        *
  2505.  ****************************************************************************/
  2506.  
  2507. static PCHAR ScanSystemConfig ( PCHAR Keyword )
  2508. {
  2509.  /***************************************************************************
  2510.   * Local Declarations                                *
  2511.   ***************************************************************************/
  2512.  
  2513.   static char Buffer [500] ;
  2514.   FILE *File ;
  2515.   SEL GlobalSelector ;
  2516.   SEL LocalSelector ;
  2517.   char Path [_MAX_PATH] ;
  2518.   GINFOSEG FAR *pGlobalInfoSeg ;
  2519.  
  2520.  /***************************************************************************
  2521.   * Get the boot drive number from the global information segment.        *
  2522.   ***************************************************************************/
  2523.  
  2524.   DosGetInfoSeg ( &GlobalSelector, &LocalSelector ) ;
  2525.  
  2526.   pGlobalInfoSeg = MAKEPGINFOSEG ( GlobalSelector ) ;
  2527.  
  2528.  /***************************************************************************
  2529.   * Build the CONFIG.SYS path.                            *
  2530.   ***************************************************************************/
  2531.  
  2532.   Path[0] = (char) ( pGlobalInfoSeg->bootdrive + 'A' - 1 ) ;
  2533.   Path[1] = 0 ;
  2534.   strcat ( Path, ":\\CONFIG.SYS" ) ;
  2535.  
  2536.  /***************************************************************************
  2537.   * Open CONFIG.SYS for reading.                        *
  2538.   ***************************************************************************/
  2539.  
  2540.   File = fopen ( Path, "rt" ) ;
  2541.   if ( NOT File )
  2542.   {
  2543.     return ( NULL ) ;
  2544.   }
  2545.  
  2546.  /***************************************************************************
  2547.   * While there're more lines in CONFIG.SYS, read a line and check it.      *
  2548.   ***************************************************************************/
  2549.  
  2550.   while ( fgets ( Buffer, sizeof(Buffer), File ) )
  2551.   {
  2552.  
  2553.    /*************************************************************************
  2554.     * Clean any trailing newline character from the input string.        *
  2555.     *************************************************************************/
  2556.  
  2557.     if ( Buffer[strlen(Buffer)-1] == '\n' )
  2558.     {
  2559.       Buffer[strlen(Buffer)-1] = 0 ;
  2560.     }
  2561.  
  2562.    /*************************************************************************
  2563.     * If keyword starts the line, we've found the line we want.  Close      *
  2564.     *    the file and return a pointer to the parameter text.            *
  2565.     *************************************************************************/
  2566.  
  2567.     if ( NOT strnicmp ( Buffer, Keyword, strlen(Keyword) )
  2568.       AND ( Buffer[strlen(Keyword)] == '=' ) )
  2569.     {
  2570.       fclose ( File ) ;
  2571.       return ( Buffer + strlen(Keyword) + 1 ) ;
  2572.     }
  2573.   }
  2574.  
  2575.  /***************************************************************************
  2576.   * Close the file.  We haven't found the line we wanted.                   *
  2577.   ***************************************************************************/
  2578.  
  2579.   fclose ( File ) ;
  2580.  
  2581.   return ( NULL ) ;
  2582. }
  2583.  
  2584. /****************************************************************************
  2585.  *                                        *
  2586.  *             Resize Client Window                    *
  2587.  *                                        *
  2588.  ****************************************************************************/
  2589.  
  2590. static void ResizeWindow ( HWND hwnd, PPROFILE Profile )
  2591. {
  2592.  /***************************************************************************
  2593.   * Local Declarations                                *
  2594.   ***************************************************************************/
  2595.  
  2596.   SHORT Count ;
  2597.   SHORT fHadToHide = FALSE ;
  2598.   SHORT fHadToRestore = FALSE ;
  2599.   LONG Height ;
  2600.   HPS hPS ;
  2601.   HWND hwndFrame ;
  2602.   short i ;
  2603.   RECTL Rectangle ;
  2604.   char Text [100] ;
  2605.   LONG Widest ;
  2606.  
  2607.  /***************************************************************************
  2608.   * If the window is visible and minimized, restore it invisibly.        *
  2609.   ***************************************************************************/
  2610.  
  2611.   hwndFrame = WinQueryWindow ( hwnd, QW_PARENT, FALSE ) ;
  2612.  
  2613.   if ( Profile->Position.fs & SWP_MINIMIZE )
  2614.   {
  2615.     if ( WinIsWindowVisible ( hwndFrame ) )
  2616.     {
  2617.       WinShowWindow ( hwndFrame, FALSE ) ;
  2618.       fHadToHide = TRUE ;
  2619.     }
  2620.     WinSetWindowPos ( hwndFrame, NULL, 0, 0, 0, 0, SWP_RESTORE ) ;
  2621.     fHadToRestore = TRUE ;
  2622.   }
  2623.  
  2624.  /***************************************************************************
  2625.   * Determine how many items are to be displayed.                *
  2626.   ***************************************************************************/
  2627.  
  2628.   if ( DosSemRequest ( &ItemSemaphore, 5000 ) )
  2629.   {
  2630.     Log ( "ERROR: Unable to lock item list to determine window size.\n" ) ;
  2631.     DosSemRequest ( &ItemSemaphore, SEM_INDEFINITE_WAIT ) ;
  2632.   }
  2633.  
  2634.   hPS = WinGetPS ( hwnd ) ;
  2635.  
  2636.   Count = 0 ;
  2637.   Widest = 0 ;
  2638.   Height = 0 ;
  2639.  
  2640.   for ( i=0; i<Profile->ItemCount; i++ )
  2641.   {
  2642.     PITEM Item = & Profile->Items [i] ;
  2643.  
  2644.     if ( Item->Flag )
  2645.     {
  2646.       Count ++ ;
  2647.  
  2648.       sprintf ( Text, "%s 1,234,567K", Item->Label ) ;
  2649.  
  2650.       WinQueryWindowRect ( HWND_DESKTOP, &Rectangle ) ;
  2651.  
  2652.       WinDrawText ( hPS, strlen(Text), Text,
  2653.     &Rectangle, 0L, 0L, DT_LEFT | DT_BOTTOM | DT_QUERYEXTENT ) ;
  2654.  
  2655.       Widest = max ( Widest, (Rectangle.xRight-Rectangle.xLeft+1) ) ;
  2656.  
  2657.       Height += Rectangle.yTop - Rectangle.yBottom ;
  2658.     }
  2659.   }
  2660.  
  2661.   WinReleasePS ( hPS ) ;
  2662.  
  2663.   DosSemClear ( &ItemSemaphore ) ;
  2664.  
  2665.  /***************************************************************************
  2666.   * Get the window's current size & position.                               *
  2667.   ***************************************************************************/
  2668.  
  2669.   WinQueryWindowRect ( hwndFrame, &Rectangle ) ;
  2670.  
  2671.   WinCalcFrameRect ( hwndFrame, &Rectangle, TRUE ) ;
  2672.  
  2673.  /***************************************************************************
  2674.   * Adjust the window's width & height.                                     *
  2675.   ***************************************************************************/
  2676.  
  2677.   Rectangle.xRight  = Rectangle.xLeft + Widest ;
  2678.  
  2679.   Rectangle.yTop    = Rectangle.yBottom + Height ;
  2680.  
  2681.  /***************************************************************************
  2682.   * Compute new frame size and apply it.                    *
  2683.   ***************************************************************************/
  2684.  
  2685.   WinCalcFrameRect ( hwndFrame, &Rectangle, FALSE ) ;
  2686.  
  2687.   WinSetWindowPos ( hwndFrame, NULL, 0, 0,
  2688.     (SHORT) (Rectangle.xRight-Rectangle.xLeft),
  2689.     (SHORT) (Rectangle.yTop-Rectangle.yBottom),
  2690.     SWP_SIZE ) ;
  2691.  
  2692.  /***************************************************************************
  2693.   * Return the window to its original state.                    *
  2694.   ***************************************************************************/
  2695.  
  2696.   if ( fHadToRestore )
  2697.   {
  2698.     WinSetWindowPos ( hwndFrame, NULL,
  2699.       Profile->Position.x, Profile->Position.y,
  2700.       Profile->Position.cx, Profile->Position.cy,
  2701.       SWP_MOVE | SWP_SIZE | SWP_MINIMIZE ) ;
  2702.   }
  2703.  
  2704.   if ( fHadToHide )
  2705.   {
  2706.     WinShowWindow ( hwndFrame, TRUE ) ;
  2707.   }
  2708.  
  2709.  /***************************************************************************
  2710.   * Invalidate the window so that it gets repainted.                *
  2711.   ***************************************************************************/
  2712.  
  2713.   WinInvalidateRect ( hwnd, NULL, TRUE ) ;
  2714. }
  2715.  
  2716. /****************************************************************************
  2717.  *                                        *
  2718.  *            Hide Window Controls                    *
  2719.  *                                        *
  2720.  ****************************************************************************/
  2721.  
  2722. static void HideControls
  2723. (
  2724.   BOOL fHide,
  2725.   HWND hwndFrame,
  2726.   HWND hwndSysMenu,
  2727.   HWND hwndTitleBar,
  2728.   HWND hwndMinMax
  2729. )
  2730. {
  2731.  /***************************************************************************
  2732.   * Local Declarations                                *
  2733.   ***************************************************************************/
  2734.  
  2735.   SWP OldPosition ;
  2736.   SWP Position ;
  2737.   RECTL Rectangle ;
  2738.   BOOL WasVisible ;
  2739.  
  2740.  /***************************************************************************
  2741.   * Get original window position and state.                    *
  2742.   ***************************************************************************/
  2743.  
  2744.   WinQueryWindowPos ( hwndFrame, &OldPosition ) ;
  2745.  
  2746.   WasVisible = WinIsWindowVisible ( hwndFrame ) ;
  2747.  
  2748.  /***************************************************************************
  2749.   * Restore and hide the window.                        *
  2750.   ***************************************************************************/
  2751.  
  2752.   WinSetWindowPos ( hwndFrame, NULL, 0, 0, 0, 0, SWP_RESTORE | SWP_HIDE ) ;
  2753.  
  2754.  /***************************************************************************
  2755.   * Determine client window and location.                    *
  2756.   ***************************************************************************/
  2757.  
  2758.   WinQueryWindowPos ( hwndFrame, &Position ) ;
  2759.  
  2760.   Rectangle.xLeft   = Position.x ;
  2761.   Rectangle.xRight  = Position.x + Position.cx ;
  2762.   Rectangle.yBottom = Position.y ;
  2763.   Rectangle.yTop    = Position.y + Position.cy ;
  2764.  
  2765.   WinCalcFrameRect ( hwndFrame, &Rectangle, TRUE ) ;
  2766.  
  2767.  /***************************************************************************
  2768.   * Hide or reveal the controls windows by changing their parentage.        *
  2769.   ***************************************************************************/
  2770.  
  2771.   if ( fHide )
  2772.   {
  2773.     WinSetParent ( hwndSysMenu,  HWND_OBJECT, FALSE ) ;
  2774.     WinSetParent ( hwndTitleBar, HWND_OBJECT, FALSE ) ;
  2775.     WinSetParent ( hwndMinMax,     HWND_OBJECT, FALSE ) ;
  2776.   }
  2777.   else
  2778.   {
  2779.     WinSetParent ( hwndSysMenu,  hwndFrame, TRUE ) ;
  2780.     WinSetParent ( hwndTitleBar, hwndFrame, TRUE ) ;
  2781.     WinSetParent ( hwndMinMax,     hwndFrame, TRUE ) ;
  2782.   }
  2783.  
  2784.  /***************************************************************************
  2785.   * Tell the frame that things have changed.  Let it update the window.     *
  2786.   ***************************************************************************/
  2787.  
  2788.   WinSendMsg ( hwndFrame, WM_UPDATEFRAME,
  2789.     MPFROMSHORT ( FCF_TITLEBAR | FCF_SYSMENU | FCF_MINBUTTON ), 0L ) ;
  2790.  
  2791.  /***************************************************************************
  2792.   * Reposition the frame around the client window, which is left be.        *
  2793.   ***************************************************************************/
  2794.  
  2795.   WinCalcFrameRect ( hwndFrame, &Rectangle, FALSE ) ;
  2796.  
  2797.   WinSetWindowPos ( hwndFrame, NULL,
  2798.     (SHORT) Rectangle.xLeft,  (SHORT) Rectangle.yBottom,
  2799.     (SHORT) (Rectangle.xRight-Rectangle.xLeft),
  2800.     (SHORT) (Rectangle.yTop-Rectangle.yBottom),
  2801.     SWP_SIZE | SWP_MOVE ) ;
  2802.  
  2803.  /***************************************************************************
  2804.   * If window was maximized, put it back that way.                *
  2805.   ***************************************************************************/
  2806.  
  2807.   if ( OldPosition.fs & SWP_MAXIMIZE )
  2808.   {
  2809.     WinSetWindowPos ( hwndFrame, NULL,
  2810.       (SHORT) Rectangle.xLeft,    (SHORT) Rectangle.yBottom,
  2811.       (SHORT) (Rectangle.xRight-Rectangle.xLeft),
  2812.       (SHORT) (Rectangle.yTop-Rectangle.yBottom),
  2813.       SWP_SIZE | SWP_MOVE |
  2814.       ( OldPosition.fs & SWP_MAXIMIZE ) ) ;
  2815.   }
  2816.  
  2817.  /***************************************************************************
  2818.   * If the window was visible in the first place, show it.            *
  2819.   ***************************************************************************/
  2820.  
  2821.   if ( WasVisible )
  2822.   {
  2823.     WinShowWindow ( hwndFrame, TRUE ) ;
  2824.   }
  2825. }
  2826.  
  2827. /****************************************************************************
  2828.  *                                        *
  2829.  *    Update Window                                *
  2830.  *                                        *
  2831.  ****************************************************************************/
  2832.  
  2833. #pragma optimize ( "gle", off )
  2834.  
  2835. static void UpdateWindow ( HWND hwnd, PDATA Data, BOOL All )
  2836. {
  2837.  /***************************************************************************
  2838.   *                Declarations                    *
  2839.   ***************************************************************************/
  2840.  
  2841.   int Count ;
  2842.   HPS hPS ;
  2843.   short i ;
  2844.   RECTL Rectangle ;
  2845.   char Text [100] ;
  2846.  
  2847.  /***************************************************************************
  2848.   * Lock the item list.                             *
  2849.   ***************************************************************************/
  2850.  
  2851.   if ( DosSemRequest ( &ItemSemaphore, 5000 ) )
  2852.   {
  2853.     Log ( "ERROR: Unable to lock item list to update window contents.\n" ) ;
  2854.     DosSemRequest ( &ItemSemaphore, SEM_INDEFINITE_WAIT ) ;
  2855.   }
  2856.  
  2857.  /***************************************************************************
  2858.   * Determine how many items are to be displayed.                *
  2859.   ***************************************************************************/
  2860.  
  2861.   Count = 0 ;
  2862.   for ( i=0; i<Data->Profile.ItemCount; i++ )
  2863.   {
  2864.     if ( Data->Profile.Items[i].Flag )
  2865.     {
  2866.       Count ++ ;
  2867.     }
  2868.   }
  2869.  
  2870.  /***************************************************************************
  2871.   * Get presentation space and make it use RGB colors.                *
  2872.   ***************************************************************************/
  2873.  
  2874.   hPS = WinGetPS ( hwnd ) ;
  2875.   GpiCreateLogColorTable ( hPS, LCOL_RESET, LCOLF_RGB, 0L, 0L, NULL ) ;
  2876.  
  2877.  /***************************************************************************
  2878.   * Get the window's size and determine the initial position.               *
  2879.   ***************************************************************************/
  2880.  
  2881.   WinQueryWindowRect ( hwnd, &Rectangle ) ;
  2882.  
  2883.   Rectangle.xLeft += Data->Width / 2 ;
  2884.   Rectangle.xRight -= Data->Width / 2 ;
  2885.  
  2886.   Rectangle.yBottom = Data->Height * ( Count - 1 ) ;
  2887.   Rectangle.yTop = Rectangle.yBottom + Data->Height ;
  2888.  
  2889.  /***************************************************************************
  2890.   * Review all items.  Display those changed, or all.                *
  2891.   ***************************************************************************/
  2892.  
  2893.   for ( i=0; i<Data->Profile.ItemCount; i++ )
  2894.   {
  2895.     PITEM Item = & Data->Profile.Items [i] ;
  2896.     ULONG NewValue ;
  2897.  
  2898.     if ( Item->Flag )
  2899.     {
  2900.       if ( NOT Item->Error )
  2901.       {
  2902.     if ( Item->NewValue )
  2903.       NewValue = Item->NewValue ( Data, Item->Parm ) ;
  2904.     else
  2905.       Log ( "Item->NewValue == NULL!  Label '%s'.\n", Item->Label ) ;
  2906.       }
  2907.       else
  2908.       {
  2909.     NewValue = DRIVE_ERROR ;
  2910.       }
  2911.  
  2912.       if ( All OR ( NewValue != Item->Value ) )
  2913.       {
  2914.     switch ( i )
  2915.     {
  2916.       case ITEM_CLOCK:
  2917.       {
  2918.         ULONG Month  = ( NewValue % 100000000L ) / 1000000L ;
  2919.         ULONG Day     = ( NewValue % 1000000L ) / 10000L ;
  2920.         ULONG Hour     = ( NewValue % 10000L ) / 100L ;
  2921.         ULONG Minute = ( NewValue % 100L ) ;
  2922.  
  2923.         switch ( Data->CountryInfo.fsDateFmt )
  2924.         {
  2925.           case DATEFMT_DD_MM_YY:
  2926.         sprintf ( Text, "%02lu%s%02lu ",
  2927.           Day, Data->CountryInfo.szDateSeparator, Month ) ;
  2928.         break ;
  2929.  
  2930.           case DATEFMT_YY_MM_DD:
  2931.           case DATEFMT_MM_DD_YY:
  2932.           default:
  2933.         sprintf ( Text, "%02lu%s%02lu ",
  2934.           Month, Data->CountryInfo.szDateSeparator, Day ) ;
  2935.         break ;
  2936.         }
  2937.  
  2938.         if ( Data->CountryInfo.fsTimeFmt )
  2939.         {
  2940.           sprintf ( Text+strlen(Text), "%02lu%s%02lu",
  2941.         Hour,
  2942.         Data->CountryInfo.szTimeSeparator,
  2943.         Minute ) ;
  2944.         }
  2945.         else
  2946.         {
  2947.           PCHAR AmPm ;
  2948.  
  2949.           if ( Hour )
  2950.           {
  2951.         if ( Hour < 12 )
  2952.         {
  2953.           AmPm = "a" ;
  2954.         }
  2955.         else if ( Hour == 12 )
  2956.         {
  2957.           if ( Minute )
  2958.             AmPm = "p" ;
  2959.           else
  2960.             AmPm = "a" ;
  2961.         }
  2962.         else if ( Hour > 12 )
  2963.         {
  2964.           Hour -= 12 ;
  2965.           AmPm = "p" ;
  2966.         }
  2967.           }
  2968.           else
  2969.           {
  2970.         Hour = 12 ;
  2971.         if ( Minute )
  2972.           AmPm = "a" ;
  2973.         else
  2974.           AmPm = "p" ;
  2975.           }
  2976.           sprintf ( Text+strlen(Text), "%02lu%s%02lu%s",
  2977.         Hour, Data->CountryInfo.szTimeSeparator, Minute, AmPm ) ;
  2978.         }
  2979.         break ;
  2980.       }
  2981.  
  2982.       default:
  2983.       {
  2984.         memset ( Text, 0, sizeof(Text) ) ;
  2985.  
  2986.         if ( NewValue == DRIVE_ERROR )
  2987.         {
  2988.           Item->Error = TRUE ;
  2989.           WinLoadString ( Data->Anchor, Data->Library, IDS_DRIVEERROR, sizeof(Text), Text ) ;
  2990.         }
  2991.         else
  2992.         {
  2993.           if ( Item->Divisor )
  2994.           {
  2995.         if ( NewValue < Item->Divisor * 1000 )
  2996.           sprintf ( Text, "%lu", NewValue ) ;
  2997.         else
  2998.           sprintf ( Text, "%lu", (NewValue+Item->Divisor/2)/Item->Divisor ) ;
  2999.           }
  3000.           else
  3001.           {
  3002.         sprintf ( Text, "%lu", NewValue ) ;
  3003.           }
  3004.  
  3005.           {
  3006.         PCHAR p1, p2 ;
  3007.         CHAR Work[100] ;
  3008.  
  3009.         p1 = Text ;
  3010.         p2 = Work ;
  3011.         while ( *p1 )
  3012.         {
  3013.           *p2 = *p1 ;
  3014.           p1 ++ ;
  3015.           p2 ++ ;
  3016.           if ( *p1 )
  3017.           {
  3018.             if ( strlen(p1) % 3 == 0 )
  3019.             {
  3020.               *p2 = Data->CountryInfo.szThousandsSeparator [0] ;
  3021.               p2 ++ ;
  3022.             }
  3023.           }
  3024.         }
  3025.         *p2 = 0 ;
  3026.         strcpy ( Text, Work ) ;
  3027.           }
  3028.  
  3029.           if ( Item->Divisor )
  3030.           {
  3031.         if ( NewValue < Item->Divisor * 1000 )
  3032.           Text[strlen(Text)] = ' ' ;
  3033.         else
  3034.           Text[strlen(Text)] = Item->Suffix ;
  3035.           }
  3036.           else
  3037.           {
  3038.         Text[strlen(Text)] = Item->Suffix ;
  3039.           }
  3040.         }
  3041.       }
  3042.     }
  3043.  
  3044.     WinDrawText ( hPS, strlen(Text), Text, &Rectangle,
  3045.       Data->Profile.TextColor, Data->Profile.BackColor,
  3046.       DT_RIGHT | DT_BOTTOM | DT_ERASERECT ) ;
  3047.  
  3048.     WinDrawText ( hPS, strlen(Item->Label), Item->Label, &Rectangle,
  3049.       Data->Profile.TextColor, Data->Profile.BackColor,
  3050.       DT_LEFT | DT_BOTTOM ) ;
  3051.  
  3052.     Item->Value = NewValue ;
  3053.       }
  3054.       Rectangle.yBottom -= Data->Height ;
  3055.       Rectangle.yTop    -= Data->Height ;
  3056.     }
  3057.   }
  3058.  
  3059.  /***************************************************************************
  3060.   * Release the presentation space and return.                    *
  3061.   ***************************************************************************/
  3062.  
  3063.   WinReleasePS ( hPS ) ;
  3064.  
  3065.  /***************************************************************************
  3066.   * Release the item list.                            *
  3067.   ***************************************************************************/
  3068.  
  3069.   DosSemClear ( &ItemSemaphore ) ;
  3070. }
  3071.  
  3072. #pragma optimize ( "gle", on )
  3073.  
  3074.  
  3075. /****************************************************************************
  3076.  *                                        *
  3077.  *    Compute Time                                *
  3078.  *                                        *
  3079.  ****************************************************************************/
  3080.  
  3081. static ULONG ComputeTime ( PDATA Data, USHORT Dummy )
  3082. {
  3083.   char DateString [9] ;
  3084.   short Hour, Minute ;
  3085.   short Month, Day ;
  3086.   ULONG Time ;
  3087.   char TimeString [9] ;
  3088.  
  3089.   _strdate ( DateString ) ;
  3090.   _strtime ( TimeString ) ;
  3091.  
  3092.   Hour     = atoi ( TimeString + 0 ) ;
  3093.   Minute = atoi ( TimeString + 3 ) ;
  3094.  
  3095.   Month  = atoi ( DateString + 0 ) ;
  3096.   Day     = atoi ( DateString + 3 ) ;
  3097.  
  3098.   Time = Month ;
  3099.   Time *= 100 ;
  3100.   Time += Day ;
  3101.   Time *= 100 ;
  3102.   Time += Hour ;
  3103.   Time *= 100 ;
  3104.   Time += Minute ;
  3105.  
  3106.   return ( Time ) ;
  3107. }
  3108.  
  3109. /****************************************************************************
  3110.  *                                        *
  3111.  *    Compute Available Memory                            *
  3112.  *                                        *
  3113.  ****************************************************************************/
  3114.  
  3115. static ULONG ComputeFreeMemory ( PDATA Data, USHORT Dummy )
  3116. {
  3117.   ULONG MemFree ;
  3118.  
  3119.   DosMemAvail ( &MemFree ) ;
  3120.  
  3121.   return ( MemFree ) ;
  3122. }
  3123.  
  3124. /****************************************************************************
  3125.  *                                        *
  3126.  *    Compute Swap-File Size                            *
  3127.  *                                        *
  3128.  ****************************************************************************/
  3129.  
  3130. static ULONG ComputeSwapSize ( PDATA Data, USHORT Dummy )
  3131. {
  3132.  /***************************************************************************
  3133.   *                Declarations                    *
  3134.   ***************************************************************************/
  3135.  
  3136.   char Path [_MAX_PATH+1] ;
  3137.   struct stat Status ;
  3138.   ULONG SwapSize ;
  3139.  
  3140.  /***************************************************************************
  3141.   * Find the swap file and find its size.                    *
  3142.   ***************************************************************************/
  3143.  
  3144.   strcpy ( Path, Data->SwapPath ) ;
  3145.  
  3146.   if ( Path[strlen(Path)-1] != '\\' )
  3147.   {
  3148.     strcat ( Path, "\\" ) ;
  3149.   }
  3150.  
  3151.   strcat ( Path, "SWAPPER.DAT" ) ;
  3152.  
  3153.   SwapSize = 0 ;
  3154.   if ( stat ( Path, &Status ) == 0 )
  3155.   {
  3156.     SwapSize = Status.st_size ;
  3157.   }
  3158.  
  3159.   return ( SwapSize ) ;
  3160. }
  3161.  
  3162. /****************************************************************************
  3163.  *                                        *
  3164.  *    Compute Available Swap Space                        *
  3165.  *                                        *
  3166.  ****************************************************************************/
  3167.  
  3168. static ULONG ComputeSwapFree ( PDATA Data, USHORT Dummy )
  3169. {
  3170.  /***************************************************************************
  3171.   *                Declarations                    *
  3172.   ***************************************************************************/
  3173.  
  3174.   FSALLOCATE Allocation ;
  3175.   char Path [_MAX_PATH+1] ;
  3176.   ULONG SwapFree ;
  3177.  
  3178.  /***************************************************************************
  3179.   * Find the swap file and find its size.                    *
  3180.   ***************************************************************************/
  3181.  
  3182.   strcpy ( Path, Data->SwapPath ) ;
  3183.   strcat ( Path, "\\SWAPPER.DAT" ) ;
  3184.  
  3185.  /***************************************************************************
  3186.   * Compute swap device free space.                        *
  3187.   ***************************************************************************/
  3188.  
  3189.   SwapFree = 0 ;
  3190.   if ( Path[0] )
  3191.   {
  3192.     DosError ( HARDERROR_DISABLE ) ;
  3193.     DosQFSInfo ( Path[0]-'A'+1, FSIL_ALLOC,
  3194.       (PBYTE)&Allocation, sizeof(Allocation) ) ;
  3195.     DosError ( HARDERROR_ENABLE ) ;
  3196.  
  3197.     SwapFree = Allocation.cUnitAvail*Allocation.cSectorUnit*Allocation.cbSector ;
  3198.   }
  3199.  
  3200.  /***************************************************************************
  3201.   * Return swap device's free space, less the minimum free space.           *
  3202.   ***************************************************************************/
  3203.  
  3204.   if ( SwapFree < (ULONG)Data->MinFree*1024L )
  3205.     return ( 0L ) ;
  3206.   else
  3207.     return ( SwapFree - (ULONG)Data->MinFree * 1024L ) ;
  3208. }
  3209.  
  3210. /****************************************************************************
  3211.  *                                        *
  3212.  *    Compute Spool-file Size                            *
  3213.  *                                        *
  3214.  ****************************************************************************/
  3215.  
  3216. static ULONG ComputeSpoolSize ( PDATA Data, USHORT Dummy )
  3217. {
  3218.  /***************************************************************************
  3219.   *                Declarations                    *
  3220.   ***************************************************************************/
  3221.  
  3222.   USHORT Count ;
  3223.   FILEFINDBUF *Found ;
  3224.   HDIR hDir = HDIR_CREATE ;
  3225.   BYTE *Path ;
  3226.   USHORT PathSize ;
  3227.   ULONG TotalSize = 0 ;
  3228.  
  3229.  /***************************************************************************
  3230.   * Build file specifier for the spool directory.                *
  3231.   ***************************************************************************/
  3232.  
  3233.   DosQSysInfo ( 0, (PBYTE)&PathSize, sizeof(PathSize) ) ;
  3234.  
  3235.   Path = malloc ( PathSize ) ;
  3236.   if ( Path == NULL )
  3237.   {
  3238.     return ( 0 ) ;
  3239.   }
  3240.  
  3241.   Found = malloc ( PathSize + sizeof(FILEFINDBUF) ) ;
  3242.   if ( Found == NULL )
  3243.   {
  3244.     free ( Path ) ;
  3245.     return ( 0 ) ;
  3246.   }
  3247.  
  3248.   strcpy ( Path, Data->SpoolPath ) ;
  3249.   strcat ( Path, "\\*.*" ) ;
  3250.  
  3251.  /***************************************************************************
  3252.   * If there are any files/directories in the spool directory . . .        *
  3253.   ***************************************************************************/
  3254.  
  3255.   Count = 1 ;
  3256.   if ( !DosFindFirst2 ( Path, &hDir,
  3257.     FILE_NORMAL | FILE_READONLY | FILE_DIRECTORY | FILE_ARCHIVED,
  3258.     Found, PathSize+sizeof(FILEFINDBUF), &Count, FIL_STANDARD, 0L ) )
  3259.   {
  3260.  
  3261.    /*************************************************************************
  3262.     * Loop through every entry in the spool directory.                *
  3263.     *************************************************************************/
  3264.  
  3265.     do
  3266.     {
  3267.  
  3268.      /***********************************************************************
  3269.       * Ignore the parent and current directory entries.            *
  3270.       ***********************************************************************/
  3271.  
  3272.       if ( !strcmp ( Found->achName, "." )
  3273.     OR !strcmp ( Found->achName, ".." ) )
  3274.       {
  3275.     continue ;
  3276.       }
  3277.  
  3278.      /***********************************************************************
  3279.       * If the entry is a subdirectory . . .                    *
  3280.       ***********************************************************************/
  3281.  
  3282.       if ( Found->attrFile & FILE_DIRECTORY )
  3283.       {
  3284.  
  3285.        /*********************************************************************
  3286.     * Scan the subdirectory and add every file's size to the total.     *
  3287.     *********************************************************************/
  3288.  
  3289.     HDIR hDir = HDIR_CREATE ;
  3290.  
  3291.     strcpy ( Path, Data->SpoolPath ) ;
  3292.     strcat ( Path, "\\" ) ;
  3293.     strcat ( Path, Found->achName ) ;
  3294.     strcat ( Path, "\\*.*" ) ;
  3295.  
  3296.     Count = 1 ;
  3297.     if ( !DosFindFirst2 ( Path, &hDir,
  3298.       FILE_NORMAL | FILE_READONLY | FILE_ARCHIVED,
  3299.       Found, PathSize+sizeof(FILEFINDBUF), &Count, FIL_STANDARD, 0L ) )
  3300.     {
  3301.       do
  3302.       {
  3303.         TotalSize += Found->cbFileAlloc ;
  3304.       }
  3305.       while ( !DosFindNext ( hDir, Found, PathSize+sizeof(FILEFINDBUF), &Count ) ) ;
  3306.       DosFindClose ( hDir ) ;
  3307.     }
  3308.  
  3309.     Count = 1 ;
  3310.       }
  3311.  
  3312.      /***********************************************************************
  3313.       * Else if it was a file, add its size to the total.            *
  3314.       ***********************************************************************/
  3315.  
  3316.       else
  3317.       {
  3318.     TotalSize += Found->cbFileAlloc ;
  3319.       }
  3320.     }
  3321.     while ( !DosFindNext ( hDir, Found, PathSize+sizeof(FILEFINDBUF), &Count ) ) ;
  3322.  
  3323.    /*************************************************************************
  3324.     * Close the directory scan.                         *
  3325.     *************************************************************************/
  3326.  
  3327.     DosFindClose ( hDir ) ;
  3328.   }
  3329.  
  3330.   free ( Path ) ;
  3331.   free ( Found ) ;
  3332.  
  3333.   return ( TotalSize ) ;
  3334. }
  3335.  
  3336. /****************************************************************************
  3337.  *                                        *
  3338.  *    Compute CPU Load                                *
  3339.  *                                        *
  3340.  ****************************************************************************/
  3341.  
  3342. static ULONG ComputeCpuLoad ( PDATA Data, USHORT Dummy )
  3343. {
  3344.   ULONG Load ;
  3345.  
  3346.   Data->MaxCount = (ULONG) max ( Data->MaxCount, Data->IdleCount ) ;
  3347.  
  3348.   Load = ( ( Data->MaxCount - Data->IdleCount ) * 100 ) / Data->MaxCount ;
  3349.  
  3350.   return ( Load ) ;
  3351. }
  3352.  
  3353. /****************************************************************************
  3354.  *                                        *
  3355.  *    Compute Active Task Count                         *
  3356.  *                                        *
  3357.  ****************************************************************************/
  3358.  
  3359. static ULONG ComputeTaskCount ( PDATA Data, USHORT Dummy )
  3360. {
  3361.   return ( WinQuerySwitchList ( Data->Anchor, NULL, 0 ) ) ;
  3362. }
  3363.  
  3364. /****************************************************************************
  3365.  *                                        *
  3366.  *    Compute Drive Free Space                            *
  3367.  *                                        *
  3368.  ****************************************************************************/
  3369.  
  3370. static ULONG ComputeDriveFree ( PDATA Data, USHORT Drive )
  3371. {
  3372.   FSALLOCATE Allocation ;
  3373.   USHORT Status ;
  3374.  
  3375.   DosError ( HARDERROR_DISABLE ) ;
  3376.   Status = DosQFSInfo ( Drive, FSIL_ALLOC, (PBYTE)&Allocation, sizeof(Allocation) ) ;
  3377.   DosError ( HARDERROR_ENABLE ) ;
  3378.  
  3379.   if ( Status )
  3380.   {
  3381.     return ( DRIVE_ERROR ) ;
  3382.   }
  3383.  
  3384.   DosError ( HARDERROR_ENABLE ) ;
  3385.   return ( Allocation.cUnitAvail*Allocation.cSectorUnit*Allocation.cbSector ) ;
  3386. }
  3387.  
  3388. /****************************************************************************
  3389.  *                                        *
  3390.  *    Monitor Loop Thread                            *
  3391.  *                                        *
  3392.  ****************************************************************************/
  3393.  
  3394. static void _far _cdecl MonitorLoopThread ( PMONITOR_PARMS Parms )
  3395. {
  3396.  /***************************************************************************
  3397.   * Local Declarations                                *
  3398.   ***************************************************************************/
  3399.  
  3400.   ULONG     Counter ;
  3401.   ULONG     CurrentCounter ;
  3402.   ULONG     DeltaMilliseconds ;
  3403.   BOOL        HiResTimer ;
  3404.   ULONG     LastCounter ;
  3405.   ULONG     LastMilliseconds ;
  3406.   ULONG     Nanoseconds ;
  3407.   PGINFOSEG pGlobalInfoSeg = NULL ;
  3408.   PLINFOSEG pLocalInfoSeg = NULL ;
  3409.   TIMESTAMP Time [2] ;
  3410.  
  3411.  /***************************************************************************
  3412.   * Set this thread's priority as high as it can go.                        *
  3413.   ***************************************************************************/
  3414.  
  3415.   DosSetPrty ( PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM, *_threadid  ) ;
  3416.  
  3417.  /***************************************************************************
  3418.   * Get pointer to global information segment, where the time is kept.        *
  3419.   ***************************************************************************/
  3420.  
  3421.   DosGetInfoSeg ( &SELECTOROF(pGlobalInfoSeg), &SELECTOROF(pLocalInfoSeg) ) ;
  3422.  
  3423.  /***************************************************************************
  3424.   * Start up the high resolution timer, if it is available.            *
  3425.   ***************************************************************************/
  3426.  
  3427.   HiResTimer = OpenTimer ( ) ;
  3428.  
  3429.  /***************************************************************************
  3430.   * Loop forever . . .                                *
  3431.   ***************************************************************************/
  3432.  
  3433.   while ( 1 )
  3434.   {
  3435.  
  3436.    /*************************************************************************
  3437.     * Reset the last time and count seen.                    *
  3438.     *************************************************************************/
  3439.  
  3440.     if ( HiResTimer )
  3441.       GetTime ( &Time[0] ) ;
  3442.     else
  3443.       LastMilliseconds = pGlobalInfoSeg->msecs ;
  3444.  
  3445.     LastCounter = *Parms->Counter ;
  3446.  
  3447.    /*************************************************************************
  3448.     * Sleep for a bit.                                *
  3449.     *************************************************************************/
  3450.  
  3451.     DosSleep ( *Parms->Interval ) ;
  3452.  
  3453.    /*************************************************************************
  3454.     * Find out how much time and counts went by.                *
  3455.     *************************************************************************/
  3456.  
  3457.     CurrentCounter = *Parms->Counter ;
  3458.  
  3459.     if ( HiResTimer )
  3460.     {
  3461.       GetTime ( &Time[1] ) ;
  3462.       DeltaMilliseconds = ElapsedTime ( &Time[0], &Time[1], &Nanoseconds ) ;
  3463.       if ( Nanoseconds >= 500000L )
  3464.     DeltaMilliseconds ++ ;
  3465.     }
  3466.     else
  3467.     {
  3468.       DeltaMilliseconds = pGlobalInfoSeg->msecs - LastMilliseconds ;
  3469.     }
  3470.  
  3471.    /*************************************************************************
  3472.     * Find out how much idle time was counted.    Adjust it to persecond.     *
  3473.     *************************************************************************/
  3474.  
  3475.     Counter = ( (CurrentCounter-LastCounter) * 1000 ) / DeltaMilliseconds ;
  3476.  
  3477.    /*************************************************************************
  3478.     * Tell the owner window to refresh its statistics.                *
  3479.     *************************************************************************/
  3480.  
  3481.     WinPostMsg ( Parms->Owner, WM_REFRESH, MPFROMLONG(Counter), 0L ) ;
  3482.   }
  3483. }
  3484.  
  3485. /****************************************************************************
  3486.  *                                        *
  3487.  *    Update the Item List to reflect changes in the available drives.    *
  3488.  *                                        *
  3489.  ****************************************************************************/
  3490.  
  3491. static VOID UpdateDriveList
  3492. (
  3493.   HAB Anchor,
  3494.   HMODULE Library,
  3495.   PPROFILE Profile,
  3496.   ULONG OldDrives,
  3497.   ULONG NewDrives
  3498. )
  3499. {
  3500.  /***************************************************************************
  3501.   * Local Declarations                                *
  3502.   ***************************************************************************/
  3503.  
  3504.   USHORT Count ;
  3505.   USHORT Drive ;
  3506.   BYTE FileSystem [80] ;
  3507.   SHORT i ;
  3508.   USHORT OldCount ;
  3509.   USHORT OldIndex ;
  3510.   ITEM OldItems [ ITEM_BASE_COUNT + MAX_DRIVES ] ;
  3511.   ULONG Size ;
  3512.  
  3513.   CHAR LabelFormat [80] ;
  3514.   CHAR OptionFormat [80] ;
  3515.  
  3516.  /***************************************************************************
  3517.   * Lock the item list.                             *
  3518.   ***************************************************************************/
  3519.  
  3520.   if ( DosSemRequest ( &ItemSemaphore, 5000 ) )
  3521.   {
  3522.     Log ( "ERROR: Unable to lock item list to update the drive list.\n" ) ;
  3523.     DosSemRequest ( &ItemSemaphore, SEM_INDEFINITE_WAIT ) ;
  3524.   }
  3525.  
  3526.  /***************************************************************************
  3527.   * Get format strings.                             *
  3528.   ***************************************************************************/
  3529.  
  3530.   WinLoadString ( Anchor, Library, IDS_SHOW_DRIVE_FREE_LABEL, sizeof(LabelFormat), LabelFormat ) ;
  3531.   WinLoadString ( Anchor, Library, IDS_SHOW_DRIVE_FREE_OPTION, sizeof(OptionFormat), OptionFormat ) ;
  3532.  
  3533.  /***************************************************************************
  3534.   * Save the old item list for comparison.                    *
  3535.   ***************************************************************************/
  3536.  
  3537.   OldCount = 0 ;
  3538.   memset ( OldItems, 0, sizeof(OldItems) ) ;
  3539.  
  3540.   if ( OldDrives )
  3541.   {
  3542.     OldCount = Profile->ItemCount ;
  3543.     memcpy ( OldItems, Items, sizeof(OldItems) ) ;
  3544.   }
  3545.  
  3546.  /***************************************************************************
  3547.   * Add items for each drive on the system.                    *
  3548.   ***************************************************************************/
  3549.  
  3550.   Count = ITEM_BASE_COUNT ;
  3551.   OldIndex = ITEM_BASE_COUNT ;
  3552.  
  3553.   NewDrives >>= 2 ;
  3554.   OldDrives >>= 2 ;
  3555.  
  3556.   for ( Drive=3; Drive<MAX_DRIVES; Drive++ )
  3557.   {
  3558.     while ( ( OldIndex < OldCount )
  3559.       AND ( (SHORT)OldItems[OldIndex].MenuId < IDM_SHOW_DRIVE_FREE + Drive ) )
  3560.     {
  3561.       OldIndex ++ ;
  3562.     }
  3563.  
  3564.     if ( NewDrives & 1 )
  3565.     {
  3566.       if ( OldDrives & 1 )
  3567.       {
  3568.     Items[Count++] = OldItems[OldIndex++] ;
  3569.       }
  3570.       else
  3571.       {
  3572.     if ( CheckDrive ( Drive, FileSystem ) )
  3573.     {
  3574.       sprintf ( Items[Count].Name,         "ShowDrive%c:", Drive+'A'-1 ) ;
  3575.       sprintf ( Items[Count].Label,      LabelFormat,    Drive+'A'-1, FileSystem ) ;
  3576.       sprintf ( Items[Count].MenuOption, OptionFormat,   Drive+'A'-1 ) ;
  3577.  
  3578.       Items[Count].MenuId = IDM_SHOW_DRIVE_FREE + Drive ;
  3579.       Items[Count].NewValue = ComputeDriveFree ;
  3580.       Items[Count].Parm = Drive ;
  3581.       Items[Count].Divisor = 1024 ;
  3582.       Items[Count].Suffix = 'K' ;
  3583.       Items[Count].Error = FALSE ;
  3584.       Count ++ ;
  3585.     }
  3586.       }
  3587.     }
  3588.  
  3589.     NewDrives >>= 1 ;
  3590.     OldDrives >>= 1 ;
  3591.   }
  3592.  
  3593.  /***************************************************************************
  3594.   * Save pointer to fixed configuration information.                *
  3595.   ***************************************************************************/
  3596.  
  3597.   Profile->Items = Items ;
  3598.   Profile->ItemCount = Count ;
  3599.  
  3600.  /***************************************************************************
  3601.   * Fetch the display flags for the drives.                    *
  3602.   ***************************************************************************/
  3603.  
  3604.   for ( i=ITEM_BASE_COUNT; i<Profile->ItemCount; i++ )
  3605.   {
  3606.     PITEM Item = & Profile->Items [i] ;
  3607.  
  3608.     Item->Flag = TRUE ;
  3609.     if
  3610.     (
  3611.       PrfQueryProfileSize ( HINI_PROFILE, PROGRAM_NAME, Item->Name, &Size )
  3612.       AND
  3613.       ( Size == sizeof(Item->Flag) )
  3614.       AND
  3615.       PrfQueryProfileData ( HINI_PROFILE, PROGRAM_NAME, Item->Name, &Item->Flag, &Size )
  3616.     )
  3617.     {
  3618.       ;
  3619.     }
  3620.   }
  3621.  
  3622.  /***************************************************************************
  3623.   * Release the item list.                            *
  3624.   ***************************************************************************/
  3625.  
  3626.   DosSemClear ( &ItemSemaphore ) ;
  3627. }
  3628.  
  3629. /****************************************************************************
  3630.  *                                        *
  3631.  *    Check to see if drive should be added to display list.            *
  3632.  *                                        *
  3633.  ****************************************************************************/
  3634.  
  3635. static BOOL CheckDrive ( USHORT Drive, PBYTE FileSystem )
  3636. {
  3637.  /***************************************************************************
  3638.   * Local Declarations                                *
  3639.   ***************************************************************************/
  3640.  
  3641.   USHORT           Action ;
  3642.   BOOL               Addit ;
  3643.   CHAR               Buffer [1024] ;
  3644.   BIOSPARAMETERBLOCK   BiosParms ;
  3645.   USHORT           cbName ;
  3646.   BYTE               Command ;
  3647.   USHORT           Handle ;
  3648.   USHORT           Size ;
  3649.   USHORT           Status ;
  3650.   BYTE               Path [3] ;
  3651.  
  3652.  /***************************************************************************
  3653.   * First, check to see if drive is local or remote.  Remote drives are     *
  3654.   *   always monitored.                             *
  3655.   ***************************************************************************/
  3656.  
  3657.   Path[0] = (BYTE) ( Drive + 'A' - 1 ) ;
  3658.   Path[1] = ':' ;
  3659.   Path[2] = 0 ;
  3660.  
  3661.   DosError ( HARDERROR_DISABLE ) ;
  3662.   Size = sizeof(Buffer) ;
  3663.   Status = DosQFSAttach ( Path, 0, FSAIL_QUERYNAME, Buffer, &Size, 0 ) ;
  3664.   DosError ( HARDERROR_ENABLE ) ;
  3665.  
  3666.   if ( Status )
  3667.   {
  3668.     Log ( "ERROR: Unable to query drive %s for file system.  Status %04X.\n",
  3669.       Path, Status ) ;
  3670.     return ( FALSE ) ;
  3671.   }
  3672.  
  3673.   cbName = ((FSQBUFFER*)Buffer)->cbName ;
  3674.   strcpy ( FileSystem, ((FSQBUFFER*)(Buffer+cbName))->szFSDName ) ;
  3675.  
  3676.   if ( ((FSQBUFFER*)Buffer)->iType == FSAT_REMOTEDRV )
  3677.   {
  3678.     return ( TRUE ) ;
  3679.   }
  3680.  
  3681.  /***************************************************************************
  3682.   * Attempt to open the local drive as an entire device.  If unable to do   *
  3683.   *   so, we cannot monitor this drive.                     *
  3684.   ***************************************************************************/
  3685.  
  3686.   if ( DosOpen ( Path, &Handle, &Action, 0, 0, FILE_OPEN,
  3687.     OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE |
  3688.     OPEN_FLAGS_DASD | OPEN_FLAGS_FAIL_ON_ERROR, 0 ) )
  3689.   {
  3690.     return ( FALSE ) ;
  3691.   }
  3692.  
  3693.  /***************************************************************************
  3694.   * Check to see if the drive has removable media.  We cannot monitor such. *
  3695.   ***************************************************************************/
  3696.  
  3697.   Addit = FALSE ;
  3698.  
  3699.   Command = 0 ;
  3700.   if ( !DosDevIOCtl ( &BiosParms, &Command, DSK_GETDEVICEPARAMS, IOCTL_DISK, Handle ) )
  3701.   {
  3702.     if ( BiosParms.fsDeviceAttr & 1 )  // Must be FIXED drive.
  3703.     {
  3704.       Addit = TRUE ;
  3705.     }
  3706.   }
  3707.  
  3708.  /***************************************************************************
  3709.   * Close the drive.                                *
  3710.   ***************************************************************************/
  3711.  
  3712.   DosClose ( Handle ) ;
  3713.  
  3714.  /***************************************************************************
  3715.   * Return the final verdict.                            *
  3716.   ***************************************************************************/
  3717.  
  3718.   return ( Addit ) ;
  3719. }
  3720.  
  3721. /****************************************************************************
  3722.  *                                        *
  3723.  *    Rebuild the Display Items submenu.                    *
  3724.  *                                        *
  3725.  ****************************************************************************/
  3726.  
  3727. static VOID RebuildDisplayItems ( HWND hwnd, PDATA Data )
  3728. {
  3729.  /***************************************************************************
  3730.   * Local Declarations                                *
  3731.   ***************************************************************************/
  3732.  
  3733.   HWND       Frame ;
  3734.   SHORT    i ;
  3735.   HWND       ItemMenu ;
  3736.   MENUITEM MenuItem ;
  3737.   HWND       SysMenu ;
  3738.  
  3739.  /***************************************************************************
  3740.   * Lock the item list.                             *
  3741.   ***************************************************************************/
  3742.  
  3743.   if ( DosSemRequest ( &ItemSemaphore, 5000 ) )
  3744.   {
  3745.     Log ( "ERROR: Unable to lock item list to rebuild the display item menu.\n" ) ;
  3746.     DosSemRequest ( &ItemSemaphore, SEM_INDEFINITE_WAIT ) ;
  3747.   }
  3748.  
  3749.  /***************************************************************************
  3750.   * Find the item menu's handle.                                            *
  3751.   ***************************************************************************/
  3752.  
  3753.   Frame = WinQueryWindow ( hwnd, QW_PARENT, FALSE ) ;
  3754.  
  3755.   SysMenu = WinWindowFromID ( Frame, FID_SYSMENU ) ;
  3756.  
  3757.   WinSendMsg ( SysMenu, MM_QUERYITEM,
  3758.     MPFROM2SHORT ( IDM_DISPLAY_ITEMS, TRUE ),
  3759.     (MPARAM) &MenuItem ) ;
  3760.   ItemMenu = MenuItem.hwndSubMenu ;
  3761.  
  3762.  /***************************************************************************
  3763.   * Remove all items from the menu.                        *
  3764.   ***************************************************************************/
  3765.  
  3766.   if ( WinSendMsg ( ItemMenu, MM_QUERYITEMCOUNT, 0, 0 ) )
  3767.   {
  3768.     USHORT Id ;
  3769.     SHORT ItemsLeft ;
  3770.  
  3771.     do
  3772.     {
  3773.       Id = SHORT1FROMMR ( WinSendMsg ( ItemMenu, MM_ITEMIDFROMPOSITION,
  3774.     0, 0 ) ) ;
  3775.  
  3776.       ItemsLeft = SHORT1FROMMR ( WinSendMsg ( ItemMenu, MM_DELETEITEM,
  3777.     MPFROM2SHORT(Id,FALSE), 0 ) ) ;
  3778.     }
  3779.     while ( ItemsLeft ) ;
  3780.   }
  3781.  
  3782.  /***************************************************************************
  3783.   * Prepare menu item structure for use.                    *
  3784.   ***************************************************************************/
  3785.  
  3786.   MenuItem.iPosition = MIT_END ;
  3787.   MenuItem.afStyle = MIS_TEXT ;
  3788.   MenuItem.afAttribute = 0 ;
  3789.   MenuItem.hwndSubMenu = NULL ;
  3790.   MenuItem.hItem = 0L ;
  3791.  
  3792.  /***************************************************************************
  3793.   * Add all menu items called for.                        *
  3794.   ***************************************************************************/
  3795.  
  3796.   for ( i=0; i<Data->Profile.ItemCount; i++ )
  3797.   {
  3798.     PITEM Item = & Data->Profile.Items [i] ;
  3799.  
  3800.     MenuItem.id = Item->MenuId ;
  3801.  
  3802.     AddSysSubMenuItem ( Frame, IDM_DISPLAY_ITEMS, &MenuItem, Item->MenuOption ) ;
  3803.  
  3804.     CheckMenuItem ( Frame, FID_SYSMENU, Item->MenuId, Item->Flag ) ;
  3805.   }
  3806.  
  3807.  /***************************************************************************
  3808.   * Split the menu if it's too tall.                                        *
  3809.   ***************************************************************************/
  3810.  
  3811.   if ( Data->Profile.ItemCount > 15 )
  3812.   {
  3813.     USHORT Midpoint = ( Data->Profile.ItemCount + 1 ) / 2 ;
  3814.     USHORT Id = Data->Profile.Items[Midpoint].MenuId ;
  3815.     MENUITEM MenuItem ;
  3816.  
  3817.     if ( WinSendMsg ( ItemMenu, MM_QUERYITEM, MPFROM2SHORT(Id,FALSE), &MenuItem ) )
  3818.     {
  3819.       MenuItem.afStyle |= MIS_BREAKSEPARATOR ;
  3820.       WinSendMsg ( ItemMenu, MM_SETITEM, MPFROM2SHORT(0,FALSE), &MenuItem ) ;
  3821.     }
  3822.   }
  3823.  
  3824.  /***************************************************************************
  3825.   * Release the item list.                            *
  3826.   ***************************************************************************/
  3827.  
  3828.   DosSemClear ( &ItemSemaphore ) ;
  3829. }
  3830.  
  3831. /****************************************************************************
  3832.  *                                        *
  3833.  *             Calibrate the Load Meter                *
  3834.  *                                        *
  3835.  ****************************************************************************/
  3836.  
  3837. static ULONG CalibrateLoadMeter ( void )
  3838. {
  3839.  /***************************************************************************
  3840.   * Local Declarations                                *
  3841.   ***************************************************************************/
  3842.  
  3843.   double    AdjustedMaxLoad = 0.0 ;
  3844.   ULONG     MaxLoad ;
  3845.   ULONG     Milliseconds ;
  3846.   ULONG     Nanoseconds ;
  3847.   TID        tidCalibrate ;
  3848.   TIMESTAMP    Time[2] ;
  3849.  
  3850.  /***************************************************************************
  3851.   * If HRTIMER.SYS has been installed . . .                    *
  3852.   ***************************************************************************/
  3853.  
  3854.   if ( OpenTimer ( ) )
  3855.   {
  3856.    /*************************************************************************
  3857.     * Increase this thread's priority to the maximum.                       *
  3858.     *************************************************************************/
  3859.  
  3860.     DosSetPrty ( PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM, *_threadid ) ;
  3861.  
  3862.    /*************************************************************************
  3863.     * Create the calibration thread and set its priority next highest.        *
  3864.     *************************************************************************/
  3865.  
  3866.     tidCalibrate = _beginthread ( CounterThread, NULL, 1024, &MaxLoad ) ;
  3867.     DosSetPrty ( PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM-1, tidCalibrate ) ;
  3868.     DosSuspendThread ( tidCalibrate ) ;
  3869.  
  3870.    /*************************************************************************
  3871.     * Reset the calibration count, get the time, and let the counter go.    *
  3872.     *************************************************************************/
  3873.  
  3874.     MaxLoad = 0 ;
  3875.     GetTime ( &Time[0] ) ;
  3876.     DosResumeThread ( tidCalibrate ) ;
  3877.  
  3878.    /*************************************************************************
  3879.     * Sleep for one second.                            *
  3880.     *************************************************************************/
  3881.  
  3882.     DosSleep ( 1000 ) ;
  3883.  
  3884.    /*************************************************************************
  3885.     * Suspend the calibration counter and get the time.             *
  3886.     *************************************************************************/
  3887.  
  3888.     DosSuspendThread ( tidCalibrate ) ;
  3889.     GetTime ( &Time[1] ) ;
  3890.  
  3891.    /*************************************************************************
  3892.     * Return priorities to normal.                        *
  3893.     *************************************************************************/
  3894.  
  3895.     DosSetPrty ( PRTYS_THREAD, PRTYC_REGULAR, 0, *_threadid ) ;
  3896.  
  3897.    /*************************************************************************
  3898.     * Get the elapsed time and adjust the calibration count.            *
  3899.     *************************************************************************/
  3900.  
  3901.     Milliseconds = ElapsedTime ( &Time[0], &Time[1], &Nanoseconds ) ;
  3902.  
  3903.     AdjustedMaxLoad = (double)MaxLoad * 1.0E9 ;
  3904.     AdjustedMaxLoad /= (double)Milliseconds*1.0E6L + (double)Nanoseconds ;
  3905.  
  3906.    /*************************************************************************
  3907.     * Close down the connection to HRTIMER.SYS.                 *
  3908.     *************************************************************************/
  3909.  
  3910.     CloseTimer ( ) ;
  3911.   }
  3912.  
  3913.  /***************************************************************************
  3914.   * Return the adjusted calibration count.  If HRTIMER was not there, it    *
  3915.   *   will be zero.                                *
  3916.   ***************************************************************************/
  3917.  
  3918.   return ( (ULONG)AdjustedMaxLoad ) ;
  3919. }
  3920.  
  3921. /****************************************************************************
  3922.  *                                        *
  3923.  *              General Purpose Counter Thread                *
  3924.  *                                        *
  3925.  ****************************************************************************/
  3926.  
  3927. static void _far _cdecl CounterThread ( PULONG Counter )
  3928. {
  3929.   while ( 1 )
  3930.   {
  3931.     (*Counter) ++ ;
  3932.   }
  3933. }
  3934.